Skip to content

Commit

Permalink
Split out emoji-autocomplete as a seperate module
Browse files Browse the repository at this point in the history
  • Loading branch information
rafd committed Nov 10, 2017
1 parent 5389613 commit 10511d3
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 135 deletions.
3 changes: 1 addition & 2 deletions project.clj
Expand Up @@ -73,8 +73,7 @@
:builds
[{:id "desktop-dev"
:figwheel {:on-jsload "braid.client.desktop.core/reload"}
:source-paths ["src/braid/client"
"src/braid/common"
:source-paths ["src/braid"
"src/retouch"]
:compiler {:main braid.client.desktop.core
:asset-path "/js/dev/desktop/"
Expand Down
5 changes: 4 additions & 1 deletion src/braid/client/desktop/core.cljs
Expand Up @@ -19,7 +19,8 @@
[braid.client.uploads.subs]
[braid.client.quests.events]
[braid.client.quests.handler :as quests]
[braid.client.quests.subs]))
[braid.client.quests.subs]
[braid.core.modules]))

(enable-console-print!)

Expand All @@ -34,6 +35,8 @@
(dispatch [:set-window-visibility
(= "visible" (.-visibilityState js/document))])))

(braid.core.modules/init)

(render)

(router/init)
Expand Down
237 changes: 111 additions & 126 deletions src/braid/client/ui/views/autocomplete.cljs
Expand Up @@ -4,9 +4,9 @@
[clj-fuzzy.metrics :as fuzzy]
[goog.string :as gstring]
[re-frame.core :refer [subscribe dispatch]]
[braid.core.api :as api]
[braid.client.schema :as schema]
[braid.client.helpers :refer [id->color debounce]]
[braid.client.emoji :as emoji])
[braid.client.helpers :refer [id->color debounce]])
(:import
[goog.events KeyCodes]))

Expand Down Expand Up @@ -47,134 +47,119 @@
(or (simple-matches? m s)
(< (fuzzy/levenshtein m s) 2)))))

(defn emoji-view
[emoji]
[:div.emoji.match
(emoji/shortcode->html (string/replace emoji #"[\(\)]" ":"))
[:div.name emoji]
[:div.extra "..."]])
(api/dispatch [:braid.core/init-state
{::autocomplete-engines []}])

(def engines
[
; /<bot-name> -> autocompletes bots
(fn [text]
(let [pattern #"^/(\w+)$"
open-group (subscribe [:open-group-id])]
(when-let [bot-name (second (re-find pattern text))]
(into ()
(comp (filter (fn [b] (fuzzy-matches? (b :nickname) bot-name)))
(map (fn [b]
{:key (constantly (b :id))
:action (fn [])
:message-transform
(fn [text]
(string/replace text pattern
(str "/" (b :nickname) " ")))
:html
(constantly
[:div.bot.match
[:img.avatar {:src (b :avatar)}]
[:div.name (b :nickname)]
[:div.extra "..."]])})))
@(subscribe [:group-bots] [open-group])))))
(api/reg-event-fx :braid.core/register-autocomplete-engine
(fn [{db :db} [_ handler]]
{:db (update db ::autocomplete-engines conj handler)}))

; ... :emoji -> autocomplete emoji
(fn [text]
(let [pattern #"\B[:(](\S{2,})$"]
(when-let [query (second (re-find pattern text))]
(->> emoji/unicode
(filter (fn [[k v]]
(simple-matches? k query)))
(map (fn [[k v]]
{:key
(fn [] k)
:action
(fn [])
:message-transform
(fn [text]
(string/replace text pattern (str k " ")))
:html
(fn []
[emoji-view (let [show-brackets? (= "(" (first text))
emoji-name (apply str (-> k rest butlast))]
(if show-brackets?
(str "(" emoji-name ")") k))
{:react-key k}])}))))))
(api/reg-sub :braid.core/autocomplete-engines
(fn [db _]
(db ::autocomplete-engines)))

; ... @<user> -> autocompletes user name
(fn [text]
(let [pattern #"\B@(\S{0,})$"]
(when-let [query (second (re-find pattern text))]
(let [group-id (subscribe [:open-group-id])]
(->> @(subscribe [:users-in-group @group-id])
(filter (fn [u]
(fuzzy-matches? (u :nickname) query)))
(map (fn [user]
{:key
(fn [] (user :id))
:action
(fn [])
:message-transform
(fn [text]
(string/replace text pattern (str "@" (user :nickname) " ")))
:html
(fn []
[:div.user.match
[:img.avatar {:src (user :avatar)}]
[:div.name (user :nickname)]
[:div.extra (user :status)]])})))))))
; /<bot-name> -> autocompletes bots
(defn bot-autocomplete-engine [text]
(let [pattern #"^/(\w+)$"
open-group (subscribe [:open-group-id])]
(when-let [bot-name (second (re-find pattern text))]
(into ()
(comp (filter (fn [b] (fuzzy-matches? (b :nickname) bot-name)))
(map (fn [b]
{:key (constantly (b :id))
:action (fn [])
:message-transform
(fn [text]
(string/replace text pattern
(str "/" (b :nickname) " ")))
:html
(constantly
[:div.bot.match
[:img.avatar {:src (b :avatar)}]
[:div.name (b :nickname)]
[:div.extra "..."]])})))
@(subscribe [:group-bots] [open-group])))))

(api/dispatch [:braid.core/register-autocomplete-engine bot-autocomplete-engine])

; ... #<tag> -> autocompletes tag
(fn [text]
(let [pattern #"\B#(\S{0,})$"]
(when-let [query (second (re-find pattern text))]
(let [open-group-id (subscribe [:open-group-id])
group-tags @(subscribe [:tags-in-group @open-group-id])
exact-match? (some #(= query (:name %)) group-tags)]
(->> group-tags
(filter (fn [t]
(fuzzy-matches? (t :name) query)))
(map (fn [tag]
{:key
(fn [] (tag :id))
; ... @<user> -> autocompletes user name
(defn user-autocomplete-engine [text]
(let [pattern #"\B@(\S{0,})$"]
(when-let [query (second (re-find pattern text))]
(let [group-id (subscribe [:open-group-id])]
(->> @(subscribe [:users-in-group @group-id])
(filter (fn [u]
(fuzzy-matches? (u :nickname) query)))
(map (fn [user]
{:key
(fn [] (user :id))
:action
(fn [])
:message-transform
(fn [text]
(string/replace text pattern (str "@" (user :nickname) " ")))
:html
(fn []
[:div.user.match
[:img.avatar {:src (user :avatar)}]
[:div.name (user :nickname)]
[:div.extra (user :status)]])})))))))

(api/dispatch [:braid.core/register-autocomplete-engine user-autocomplete-engine])

; ... #<tag> -> autocompletes tag
(defn tag-autocomplete-engine [text]
(let [pattern #"\B#(\S{0,})$"]
(when-let [query (second (re-find pattern text))]
(let [open-group-id (subscribe [:open-group-id])
group-tags @(subscribe [:tags-in-group @open-group-id])
exact-match? (some #(= query (:name %)) group-tags)]
(->> group-tags
(filter (fn [t]
(fuzzy-matches? (t :name) query)))
(map (fn [tag]
{:key
(fn [] (tag :id))
:action
(fn [])
:message-transform
(fn [text]
(string/replace text pattern (str "#" (tag :name) " ")))
:html
(fn []
[:div.tag.match
[:div.color-block
{:style
(merge
{:borderColor (id->color (tag :id))
:borderWidth "3px"
:borderStyle "solid"
:borderRadius "3px"}
(when @(subscribe [:user-subscribed-to-tag? (tag :id)])
{:backgroundColor (id->color (tag :id))}))}]
[:div.name (tag :name)]
[:div.extra (or (tag :description)
(gstring/unescapeEntities "&nbsp;"))]])}))
(cons (when-not (or exact-match? (string/blank? query))
(let [tag (merge (schema/make-tag)
{:name query
:group-id @open-group-id})]
{:key (constantly (tag :id))
:action
(fn [])
(fn []
(dispatch [:create-tag {:tag tag}]))
:message-transform
(fn [text]
(string/replace text pattern (str "#" (tag :name) " ")))
(fn [text]
(string/replace text pattern (str "#" (tag :name) " ")))
:html
(fn []
[:div.tag.match
[:div.color-block
{:style
(merge
{:borderColor (id->color (tag :id))
:borderWidth "3px"
:borderStyle "solid"
:borderRadius "3px"}
(when @(subscribe [:user-subscribed-to-tag? (tag :id)])
{:backgroundColor (id->color (tag :id))}))}]
[:div.name (tag :name)]
[:div.extra (or (tag :description)
(gstring/unescapeEntities "&nbsp;"))]])}))
(cons (when-not (or exact-match? (string/blank? query))
(let [tag (merge (schema/make-tag)
{:name query
:group-id @open-group-id})]
{:key (constantly (tag :id))
:action
(fn []
(dispatch [:create-tag {:tag tag}]))
:message-transform
(fn [text]
(string/replace text pattern (str "#" (tag :name) " ")))
:html
(fn []
[:div.tag.match
[:div.color-block
{:style {:backgroundColor (id->color (tag :id))}}]
[:div.name (str "Create tag " (tag :name))]
[:div.extra
(:name @(subscribe [:group (tag :group-id)]))]])})))
(remove nil?)
reverse)))))])
(fn []
[:div.tag.match
[:div.color-block
{:style {:backgroundColor (id->color (tag :id))}}]
[:div.name (str "Create tag " (tag :name))]
[:div.extra
(:name @(subscribe [:group (tag :group-id)]))]])})))
(remove nil?)
reverse)))))

(api/dispatch [:braid.core/register-autocomplete-engine tag-autocomplete-engine])
2 changes: 1 addition & 1 deletion src/braid/client/ui/views/message.cljs
Expand Up @@ -9,7 +9,7 @@
[cljsjs.highlight.langs.yaml]
[reagent.core :as r]
[re-frame.core :refer [dispatch subscribe]]
[braid.client.emoji :as emoji]
[braid.emoji.helpers :as emoji]
[braid.client.helpers :as helpers :refer [id->color ->color]]
[braid.client.routes :as routes]
[braid.client.ui.views.embed :refer [embed-view]]
Expand Down
8 changes: 4 additions & 4 deletions src/braid/client/ui/views/new_message.cljs
Expand Up @@ -8,8 +8,7 @@
[cljs.core.async :as async :refer [<! put! chan alts!]]
[braid.client.helpers :refer [debounce stop-event!]]
[braid.client.s3 :as s3]
[braid.client.store :as store]
[braid.client.ui.views.autocomplete :refer [engines]])
[braid.client.store :as store])
(:import
(goog.events KeyCodes)))

Expand Down Expand Up @@ -82,7 +81,8 @@
(odd? (count (re-seq #"`" txt))))

(defn wrap-autocomplete [config]
(let [autocomplete-chan (chan)
(let [engines (subscribe [:braid.core/autocomplete-engines])
autocomplete-chan (chan)
kill-chan (chan)
throttled-autocomplete-chan (debounce autocomplete-chan 100)

Expand Down Expand Up @@ -215,7 +215,7 @@
(when (= ch throttled-autocomplete-chan)
(when-not (inside-code-block? text)
(set-results!
(seq (mapcat (fn [e] (e text)) engines)))
(seq (mapcat (fn [e] (e text)) @engines)))
(highlight-first!))
(recur)))))
(go (loop []
Expand Down
11 changes: 11 additions & 0 deletions src/braid/core/api.cljs
@@ -0,0 +1,11 @@
(ns braid.core.api
(:require
[re-frame.core :as re-frame]))

(def dispatch re-frame/dispatch)
(def reg-event-fx re-frame/reg-event-fx)
(def reg-sub re-frame/reg-sub)

(reg-event-fx :braid.core/init-state
(fn [{db :db} [_ state]]
{:db (merge db state)}))
7 changes: 7 additions & 0 deletions src/braid/core/modules.cljs
@@ -0,0 +1,7 @@
(ns braid.core.modules
(:require
[braid.client.ui.views.autocomplete]
[braid.emoji.core]))

(defn init []
(braid.emoji.core/init))
41 changes: 41 additions & 0 deletions src/braid/emoji/core.cljs
@@ -0,0 +1,41 @@
(ns braid.emoji.core
(:require
[clojure.string :as string]
[braid.core.api :as api]
[braid.emoji.helpers :as helpers]))

(defn simple-matches?
[m s]
(not= -1 (.indexOf m s)))

(defn emoji-view
[emoji]
[:div.emoji.match
(helpers/shortcode->html (string/replace emoji #"[\(\)]" ":"))
[:div.name emoji]
[:div.extra "..."]])

(defn autocomplete-handler [text]
(let [pattern #"\B[:(](\S{2,})$"]
(when-let [query (second (re-find pattern text))]
(->> helpers/unicode
(filter (fn [[k v]]
(simple-matches? k query)))
(map (fn [[k v]]
{:key
(fn [] k)
:action
(fn [])
:message-transform
(fn [text]
(string/replace text pattern (str k " ")))
:html
(fn []
[emoji-view (let [show-brackets? (= "(" (first text))
emoji-name (apply str (-> k rest butlast))]
(if show-brackets?
(str "(" emoji-name ")") k))
{:react-key k}])}))))))

(defn init []
(api/dispatch [:braid.core/register-autocomplete-engine autocomplete-handler]))
@@ -1,4 +1,4 @@
(ns braid.client.emoji)
(ns braid.emoji.helpers)

(declare unicode ascii)

Expand Down

0 comments on commit 10511d3

Please sign in to comment.