Skip to content

Commit 05caa14

Browse files
committed
search field, reset on new search
1 parent fb432b2 commit 05caa14

File tree

12 files changed

+290
-197
lines changed

12 files changed

+290
-197
lines changed

app/views/cljs_om.scala.html

+1-9
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,7 @@
2525

2626
<!-- Search field in NavBar -->
2727
<div class="navbar-form pull-left col-lg-6 input-group">
28-
<form id="searchForm" class="input-group">
29-
<input type="text" id="searchField" class="form-control"
30-
placeholder="Example search: java (job OR jobs OR hiring)" />
31-
<span class="input-group-btn">
32-
<button class="btn btn-primary" type="button" onclick="BirdWatch.search()">
33-
<span class="glyphicon glyphicon-search"></span>
34-
</button>
35-
</span>
36-
</form>
28+
<div id="search"></div>
3729
</div>
3830

3931
<div class="nav-collapse">

cljs-om/src/cljs_om/core.cljs

+36-34
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,34 @@
77
(enable-console-print!)
88

99
(defn sort-by [key]
10+
"sorting function, initially comparing specified key and, if equal, favors higher ID"
1011
(fn [x y]
1112
(if (not (= (key x) (key y)))
1213
(> (key x) (key y))
1314
(> (:id x) (:id y)))))
1415

15-
(def app-state (atom {:count 0
16-
:tweets-map {}
17-
:rt-since-startup {}
18-
:by-followers (sorted-set-by (sort-by :followers_count))
19-
:by-retweets (sorted-set-by (sort-by :retweet_count))
20-
:by-rt-since-startup (sorted-set-by (sort-by :count))
21-
:by-favorites (sorted-set-by (sort-by :favorite_count))
22-
:by-id (sorted-set-by >)
23-
:n 10
24-
:sorted :by-followers}))
16+
(def initial-state {:count 0
17+
:tweets-map {}
18+
:rt-since-startup {}
19+
:by-followers (sorted-set-by (sort-by :followers_count))
20+
:by-retweets (sorted-set-by (sort-by :retweet_count))
21+
:by-rt-since-startup (sorted-set-by (sort-by :count))
22+
:by-favorites (sorted-set-by (sort-by :favorite_count))
23+
:by-id (sorted-set-by >)
24+
:n 10
25+
:sorted :by-followers
26+
:search "*"
27+
:stream nil})
2528

26-
(om/root
27-
ui/tweets-view
28-
app-state
29-
{:target (. js/document (getElementById "tweet-frame"))})
29+
(def app-state (atom initial-state))
3030

31-
(om/root
32-
ui/count-view
33-
app-state
34-
{:target (. js/document (getElementById "tweet-count"))})
35-
36-
(om/root
37-
ui/sort-buttons-view
38-
app-state
39-
{:target (. js/document (getElementById "sort-buttons"))})
31+
(om/root ui/tweets-view app-state {:target (. js/document (getElementById "tweet-frame"))})
32+
(om/root ui/count-view app-state {:target (. js/document (getElementById "tweet-count"))})
33+
(om/root ui/search-view app-state {:target (. js/document (getElementById "search"))})
34+
(om/root ui/sort-buttons-view app-state {:target (. js/document (getElementById "sort-buttons"))})
4035

4136
(defn add-to-tweets-map [tweet]
42-
(swap! app-state assoc-in [:tweets-map (keyword (:id_str tweet))] (util/format-tweet tweet)))
37+
(swap! app-state assoc-in [:tweets-map (keyword (:id_str tweet))] (util/format-tweet tweet)))
4338

4439
(defn mod-sort-set [app-key fun set-key val rt]
4540
(swap! app-state assoc app-key (fun (app-key @app-state) {set-key val :id (:id_str rt)})))
@@ -48,8 +43,9 @@
4843
"handles original, retweeted tweet"
4944
(if (contains? tweet :retweeted_status)
5045
(let [rt (:retweeted_status tweet)
51-
prev ((keyword (:id_str rt)) (:tweets-map @app-state))
52-
prev-rt-count ((keyword (:id_str rt)) (:rt-since-startup @app-state))]
46+
rt-id (keyword (:id_str rt))
47+
prev (rt-id (:tweets-map @app-state))
48+
prev-rt-count (rt-id (:rt-since-startup @app-state))]
5349
(if (not (nil? prev))
5450
(do
5551
(mod-sort-set :by-retweets disj :retweet_count (:retweet_count prev) rt)
@@ -58,9 +54,9 @@
5854
(do
5955
(if (not (nil? prev-rt-count))
6056
(mod-sort-set :by-rt-since-startup disj :count prev-rt-count rt))
61-
(swap! app-state assoc-in [:rt-since-startup (keyword (:id_str rt))]
62-
(inc ((keyword (:id_str rt)) (:rt-since-startup @app-state))))
63-
(mod-sort-set :by-rt-since-startup conj :count ((keyword (:id_str rt)) (:rt-since-startup @app-state)) rt)))
57+
(swap! app-state assoc-in [:rt-since-startup rt-id]
58+
(inc (rt-id (:rt-since-startup @app-state))))
59+
(mod-sort-set :by-rt-since-startup conj :count (rt-id (:rt-since-startup @app-state)) rt)))
6460
(add-to-tweets-map rt)
6561
(mod-sort-set :by-retweets conj :retweet_count (:retweet_count rt) rt)
6662
(mod-sort-set :by-favorites conj :favorite_count (:favorite_count rt) rt))))
@@ -80,8 +76,14 @@
8076
(let [tweet (js->clj (JSON/parse (.-data e)) :keywordize-keys true)]
8177
(add-tweet tweet)))
8278

83-
(def stream (js/EventSource. "/tweetFeed?q=*"))
84-
(.addEventListener stream
85-
"message"
86-
(fn [e] (receive-sse e))
87-
false)
79+
(defn start-search [search]
80+
"initiate new search by starting SSE stream"
81+
(let [s (if (= search "") "*" search)]
82+
(if (not (nil? (:stream @app-state))) (.close (:stream @app-state)))
83+
(reset! app-state initial-state)
84+
(swap! app-state assoc :search s)
85+
(aset js/window "location" "hash" (js/encodeURIComponent s))
86+
(swap! app-state assoc :stream (js/EventSource. (str "/tweetFeed?q=" s)))
87+
(.addEventListener (:stream @app-state) "message" (fn [e] (receive-sse e)) false)))
88+
89+
(start-search (subs (js/decodeURIComponent (aget js/window "location" "hash")) 2))

cljs-om/src/cljs_om/ui.cljs

+29-7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,31 @@
5555
(dom/button (sort-button app :by-rt-since-startup) "retweets2")
5656
(dom/button (sort-button app :by-favorites) "favorites")))))
5757

58+
(defn handle-change [e owner {:keys [text]}]
59+
(om/set-state! owner :text (.. e -target -value)))
60+
61+
(defn trigger-search [owner]
62+
(cljs-om.core/start-search (om/get-state owner :text))
63+
(om/set-state! owner :text ""))
64+
65+
(defn search-view [app owner]
66+
"rendering search bar"
67+
(reify
68+
om/IInitState
69+
(init-state [_] {:text ""})
70+
om/IRender
71+
(render [this]
72+
(dom/div #js {:className "input-group"}
73+
(dom/input #js {:className "form-control"
74+
:type "text" :ref "new-contact"
75+
:value (om/get-state owner :text)
76+
:placeholder "Example search: java (job OR jobs OR hiring)"
77+
:onKeyPress #(when (== (.-keyCode %) 13) (trigger-search owner))
78+
:onChange #(handle-change % owner)})
79+
(dom/span #js {:className "input-group-btn"}
80+
(dom/button #js {:className "btn btn-primary" :onClick #(trigger-search owner)}
81+
(dom/span #js {:className "glyphicon glyphicon-search"})))))))
82+
5883
(defn tweet-view [tweet owner]
5984
"rendering single tweet card"
6085
(reify
@@ -64,14 +89,12 @@
6489
screen-name (:screen_name user)
6590
href (str "http://www.twitter.com/" screen-name)]
6691
(dom/div #js {:className "tweet"}
67-
(dom/span nil
68-
(dom/a #js {:href href :target "_blank"}
69-
(dom/img #js {:className "thumbnail" :src (:profile_image_url user)})))
92+
(dom/span nil (dom/a #js {:href href :target "_blank"}
93+
(dom/img #js {:className "thumbnail" :src (:profile_image_url user)})))
7094
(dom/a #js {:href href :target "_blank"}
7195
(dom/span #js {:className "username" :src (:profile_image_url user)} (:name user)))
7296
(dom/span #js {:className "username_screen"} (str " @" screen-name))
73-
(dom/div #js {:className "pull-right timeInterval"}
74-
(util/from-now (:created_at tweet)))
97+
(dom/div #js {:className "pull-right timeInterval"} (util/from-now (:created_at tweet)))
7598
(dom/div #js {:className "tweettext"}
7699
(dom/div #js {:dangerouslySetInnerHTML #js {:__html (:html-text tweet)}})
77100
(dom/div #js {:className "pull-left timeInterval"}
@@ -87,5 +110,4 @@
87110
om/IRender
88111
(render [this]
89112
(dom/div nil
90-
(apply dom/div nil
91-
(om/build-all tweet-view (((:sorted app) find-tweets) app (:n app))))))))
113+
(apply dom/div nil (om/build-all tweet-view (((:sorted app) find-tweets) app (:n app))))))))

cljs-om/src/cljs_om/util.cljs

+4-12
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
(defn from-now [date]
1313
"format date using the external moment.js library"
1414
(let [time-string (. (js/moment. date) (fromNow true))]
15-
(if (= time-string "a few seconds")
16-
"just now"
17-
time-string)))
15+
(if (= time-string "a few seconds") "just now" time-string)))
1816

1917
(defn url-replacer [acc entity]
2018
"replace URL occurences in tweet texts with HTML (including links)"
@@ -48,9 +46,7 @@
4846

4947
(defn entity-count [tweet sym s]
5048
"gets count of specified entity from either tweet, or, when exists, original (retweeted) tweet"
51-
(-> (if (contains? tweet :retweeted_status)
52-
(sym (:retweeted_status tweet))
53-
(sym tweet))
49+
(-> (if (contains? tweet :retweeted_status) (sym (:retweeted_status tweet)) (sym tweet))
5450
(number-format ,)
5551
(str , s)))
5652

@@ -59,10 +55,6 @@
5955

6056
(defn rt-count-since-startup [tweet]
6157
"gets RT count since startup for tweet, if exists returns formatted string"
62-
(let [t (if (contains? tweet :retweeted_status)
63-
(:retweeted_status tweet)
64-
tweet)
58+
(let [t (if (contains? tweet :retweeted_status) (:retweeted_status tweet) tweet)
6559
count ((keyword (:id_str t)) (:rt-since-startup @cljs-om.core/app-state))]
66-
(if (> count 0)
67-
(str (number-format count) " RT since startup | ")
68-
"")))
60+
(if (> count 0) (str (number-format count) " RT since startup | ") "")))

public/cljs/out/cljs_om/core.cljs

+36-34
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,34 @@
77
(enable-console-print!)
88

99
(defn sort-by [key]
10+
"sorting function, initially comparing specified key and, if equal, favors higher ID"
1011
(fn [x y]
1112
(if (not (= (key x) (key y)))
1213
(> (key x) (key y))
1314
(> (:id x) (:id y)))))
1415

15-
(def app-state (atom {:count 0
16-
:tweets-map {}
17-
:rt-since-startup {}
18-
:by-followers (sorted-set-by (sort-by :followers_count))
19-
:by-retweets (sorted-set-by (sort-by :retweet_count))
20-
:by-rt-since-startup (sorted-set-by (sort-by :count))
21-
:by-favorites (sorted-set-by (sort-by :favorite_count))
22-
:by-id (sorted-set-by >)
23-
:n 10
24-
:sorted :by-followers}))
16+
(def initial-state {:count 0
17+
:tweets-map {}
18+
:rt-since-startup {}
19+
:by-followers (sorted-set-by (sort-by :followers_count))
20+
:by-retweets (sorted-set-by (sort-by :retweet_count))
21+
:by-rt-since-startup (sorted-set-by (sort-by :count))
22+
:by-favorites (sorted-set-by (sort-by :favorite_count))
23+
:by-id (sorted-set-by >)
24+
:n 10
25+
:sorted :by-followers
26+
:search "*"
27+
:stream nil})
2528

26-
(om/root
27-
ui/tweets-view
28-
app-state
29-
{:target (. js/document (getElementById "tweet-frame"))})
29+
(def app-state (atom initial-state))
3030

31-
(om/root
32-
ui/count-view
33-
app-state
34-
{:target (. js/document (getElementById "tweet-count"))})
35-
36-
(om/root
37-
ui/sort-buttons-view
38-
app-state
39-
{:target (. js/document (getElementById "sort-buttons"))})
31+
(om/root ui/tweets-view app-state {:target (. js/document (getElementById "tweet-frame"))})
32+
(om/root ui/count-view app-state {:target (. js/document (getElementById "tweet-count"))})
33+
(om/root ui/search-view app-state {:target (. js/document (getElementById "search"))})
34+
(om/root ui/sort-buttons-view app-state {:target (. js/document (getElementById "sort-buttons"))})
4035

4136
(defn add-to-tweets-map [tweet]
42-
(swap! app-state assoc-in [:tweets-map (keyword (:id_str tweet))] (util/format-tweet tweet)))
37+
(swap! app-state assoc-in [:tweets-map (keyword (:id_str tweet))] (util/format-tweet tweet)))
4338

4439
(defn mod-sort-set [app-key fun set-key val rt]
4540
(swap! app-state assoc app-key (fun (app-key @app-state) {set-key val :id (:id_str rt)})))
@@ -48,8 +43,9 @@
4843
"handles original, retweeted tweet"
4944
(if (contains? tweet :retweeted_status)
5045
(let [rt (:retweeted_status tweet)
51-
prev ((keyword (:id_str rt)) (:tweets-map @app-state))
52-
prev-rt-count ((keyword (:id_str rt)) (:rt-since-startup @app-state))]
46+
rt-id (keyword (:id_str rt))
47+
prev (rt-id (:tweets-map @app-state))
48+
prev-rt-count (rt-id (:rt-since-startup @app-state))]
5349
(if (not (nil? prev))
5450
(do
5551
(mod-sort-set :by-retweets disj :retweet_count (:retweet_count prev) rt)
@@ -58,9 +54,9 @@
5854
(do
5955
(if (not (nil? prev-rt-count))
6056
(mod-sort-set :by-rt-since-startup disj :count prev-rt-count rt))
61-
(swap! app-state assoc-in [:rt-since-startup (keyword (:id_str rt))]
62-
(inc ((keyword (:id_str rt)) (:rt-since-startup @app-state))))
63-
(mod-sort-set :by-rt-since-startup conj :count ((keyword (:id_str rt)) (:rt-since-startup @app-state)) rt)))
57+
(swap! app-state assoc-in [:rt-since-startup rt-id]
58+
(inc (rt-id (:rt-since-startup @app-state))))
59+
(mod-sort-set :by-rt-since-startup conj :count (rt-id (:rt-since-startup @app-state)) rt)))
6460
(add-to-tweets-map rt)
6561
(mod-sort-set :by-retweets conj :retweet_count (:retweet_count rt) rt)
6662
(mod-sort-set :by-favorites conj :favorite_count (:favorite_count rt) rt))))
@@ -80,8 +76,14 @@
8076
(let [tweet (js->clj (JSON/parse (.-data e)) :keywordize-keys true)]
8177
(add-tweet tweet)))
8278

83-
(def stream (js/EventSource. "/tweetFeed?q=*"))
84-
(.addEventListener stream
85-
"message"
86-
(fn [e] (receive-sse e))
87-
false)
79+
(defn start-search [search]
80+
"initiate new search by starting SSE stream"
81+
(let [s (if (= search "") "*" search)]
82+
(if (not (nil? (:stream @app-state))) (.close (:stream @app-state)))
83+
(reset! app-state initial-state)
84+
(swap! app-state assoc :search s)
85+
(aset js/window "location" "hash" (js/encodeURIComponent s))
86+
(swap! app-state assoc :stream (js/EventSource. (str "/tweetFeed?q=" s)))
87+
(.addEventListener (:stream @app-state) "message" (fn [e] (receive-sse e)) false)))
88+
89+
(start-search (subs (js/decodeURIComponent (aget js/window "location" "hash")) 2))

0 commit comments

Comments
 (0)