From defabeaa5d3bf473a09e3003adf4c37e45021190 Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 6 May 2022 21:10:40 +0100 Subject: [PATCH 1/2] feat: add to page --- src/cljc/athens/common_events/bfs.cljc | 11 ++++-- src/cljs/athens/events.cljs | 23 +++++++++---- .../views/blocks/autocomplete_search.cljs | 7 ++-- src/cljs/athens/views/blocks/core.cljs | 2 +- .../athens/views/blocks/textarea_keydown.cljs | 34 ++++++++++++++++++- 5 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/cljc/athens/common_events/bfs.cljc b/src/cljc/athens/common_events/bfs.cljc index 0cd34139d1..63d9e0e1f2 100644 --- a/src/cljc/athens/common_events/bfs.cljc +++ b/src/cljc/athens/common_events/bfs.cljc @@ -117,8 +117,10 @@ ;; - else the parent is the current block's parent current-block-parent? (and children open) + is-page? (common-db/get-page-title db uid) empty-block? (and (string/blank? local-str) - (empty? children)) + (empty? children) + (not is-page?)) new-block-str? (not= local-str string) ;; If block has a new local-str, write that block-save-op (when new-block-str? @@ -135,8 +137,11 @@ empty-block? current-block-parent-uid current-block-parent? uid :else current-block-parent-uid) - default-position (common-db/compat-position db {:block/uid block-position - :relation new-block-order}) + default-position (common-db/compat-position db (if is-page? + {:page/title (common-db/get-page-title db uid) + :relation :last} + {:block/uid block-position + :relation new-block-order})) ir-ops (internal-representation->atomic-ops db internal-representation default-position) remove-op (when empty-block? (graph-ops/build-block-remove-op db uid))] diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index 69999f7b85..fe4348a934 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -1625,21 +1625,22 @@ (reg-event-fx :paste-internal [(interceptors/sentry-span-no-new-tx "paste-internal")] - (fn [_ [_ uid local-str internal-representation]] + (fn [_ [_ uid local-str internal-representation target-uid skip-focus?]] (when (seq internal-representation) (let [[uid] (db/uid-and-embed-id uid) op (bfs/build-paste-op @db/dsdb - uid + (or target-uid uid) local-str internal-representation) new-titles (graph-ops/ops->new-page-titles op) new-uids (graph-ops/ops->new-block-uids op) [_rm add] (graph-ops/structural-diff @db/dsdb op) event (common-events/build-atomic-event op) - focus-uid (-> (graph-ops/contains-op? op :block/new) - first - :op/args - :block/uid)] + focus-uid (when-not skip-focus? + (-> (graph-ops/contains-op? op :block/new) + first + :op/args + :block/uid))] (log/debug "paste internal event is" (pr-str event)) {:fx [[:async-flow {:id :paste-internal-async-flow :db-path [:async-flow :paste-internal] @@ -1764,3 +1765,13 @@ (atomic-graph-ops/make-block-open-op block-uid open?))] {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + +(rf/reg-event-fx + :add-to + [(interceptors/sentry-span-no-new-tx "add-to")] + (fn [_ [_ string uid page-title]] + (log/debug ":add-to args" uid page-title) + (let [page-uid (common-db/get-page-uid @db/dsdb page-title) + ref-ir [{:block/uid (common.utils/gen-block-uid) + :block/string (str "((" uid "))")}]] + {:fx [[:dispatch [:paste-internal uid string ref-ir page-uid true]]]}))) diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index ee2a445ba9..d06164bfae 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -13,6 +13,7 @@ f (case (:search/type @state) :hashtag textarea-keydown/auto-complete-hashtag :template textarea-keydown/auto-complete-template + :add-to textarea-keydown/auto-complete-add-to textarea-keydown/auto-complete-inline)] (f state target expansion))) @@ -22,7 +23,7 @@ (fn [block state] (let [{:keys [last-e]} @state {:search/keys [index results type query]} @state - is-open (some #(= % type) [:page :block :hashtag :template])] + is-open (some #(= % type) [:page :block :hashtag :template :add-to])] [:> Autocomplete {:event last-e :isOpen is-open :onClose #(swap! state assoc :search/type false)} @@ -32,7 +33,9 @@ [:> Text {:py "0.4rem" :px "0.8rem" :fontStyle "italics"} - (str "Search for a " (symbol type))] + (str "Search for a " (if (= type :add-to) + "page to add to" + (symbol type)))] (doall (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] [:> AutocompleteButton {:key (str "inline-search-item" uid) diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index 1516e7f5f5..c8bbeb5141 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -290,7 +290,7 @@ {:block/keys [uid original-uid]} block state (r/atom {:string/local nil :string/previous nil - ;; one of #{:page :block :slash :hashtag :template} + ;; one of #{:page :block :slash :hashtag :template :add-to} :search/type nil :search/results nil :search/query nil diff --git a/src/cljs/athens/views/blocks/textarea_keydown.cljs b/src/cljs/athens/views/blocks/textarea_keydown.cljs index e8d6a3eb90..9bcb2e77d5 100644 --- a/src/cljs/athens/views/blocks/textarea_keydown.cljs +++ b/src/cljs/athens/views/blocks/textarea_keydown.cljs @@ -133,12 +133,14 @@ :page db/search-in-node-title :hashtag db/search-in-node-title :template db/search-in-block-content + :add-to db/search-in-node-title :slash filter-slash-options) regex (case type :block #"(?s).*\(\(" :page #"(?s).*\[\[" :hashtag #"(?s).*#" :template #"(?s).*;;" + :add-to #"(?s).*\+" :slash #"(?s).*/") find (re-find regex head) query-start-idx (count find) @@ -302,6 +304,28 @@ (swap! state assoc :search/type nil)))))) +;; see `auto-complete-slash` for how this arity-overloaded +;; function is used. +(defn auto-complete-add-to + ([state e] + (let [{:search/keys [index results]} @state + target (.. e -target) + {:keys [node/title]} (nth results index nil) + expansion title] + (auto-complete-add-to state target expansion))) + + ([state target expansion] + (let [{:keys [start head]} (destruct-target target) + start-idx (count (re-find #"(?s).*\+" head))] + (if (nil? expansion) + (swap! state assoc :search/type nil) + (do + (set-selection target start-idx start) + (replace-selection-with (str "[[" expansion "]]")) + (swap! state assoc :search/type nil) + (dispatch [:add-to (:string/local @state) (:block/uid @state) expansion])))))) + + ;; Arrow Keys @@ -492,7 +516,8 @@ :page (auto-complete-inline state e) :block (auto-complete-inline state e) :hashtag (auto-complete-hashtag state e) - :template (auto-complete-template state e)) + :template (auto-complete-template state e) + :add-to (auto-complete-add-to state e)) ;; shift-enter: add line break to textarea and move cursor to the next line. shift (replace-selection-with "\n") ;; cmd-enter: cycle todo states, then move cursor to the end of the line. @@ -760,6 +785,8 @@ (and (= "#" look-behind-char) (= type :hashtag)) (swap! state assoc :search/type nil) ;; semicolon: close dropdown (and (= ";" look-behind-char) (= type :template)) (swap! state assoc :search/type nil) + ;; plus: close dropdown + (and (= "+" look-behind-char) (= type :at)) (swap! state assoc :search/type nil) ;; dropdown is open: update query type (update-query state head "" type)))) @@ -801,6 +828,11 @@ :search/query "" :search/type :template :search/results []) + (and (= key "+") (nil? type)) (swap! state assoc + :search/index 0 + :search/query "" + :search/type :add-to + :search/results []) type (update-query state head key type)))) From 1433b032fea9211ddd7a17fef0f795160758039f Mon Sep 17 00:00:00 2001 From: Filipe Silva Date: Fri, 20 May 2022 11:21:31 +0100 Subject: [PATCH 2/2] fix: add-to should use slash command instead of custom syntax --- .../views/blocks/autocomplete_search.cljs | 2 +- .../athens/views/blocks/textarea_keydown.cljs | 27 +++++++++---------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index d06164bfae..1662edffaf 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -34,7 +34,7 @@ :px "0.8rem" :fontStyle "italics"} (str "Search for a " (if (= type :add-to) - "page to add to" + "page to add a reference to" (symbol type)))] (doall (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] diff --git a/src/cljs/athens/views/blocks/textarea_keydown.cljs b/src/cljs/athens/views/blocks/textarea_keydown.cljs index 9bcb2e77d5..a8980816eb 100644 --- a/src/cljs/athens/views/blocks/textarea_keydown.cljs +++ b/src/cljs/athens/views/blocks/textarea_keydown.cljs @@ -1,6 +1,6 @@ (ns athens.views.blocks.textarea-keydown (:require - ["/components/Icons/Icons" :refer [TimeNowIcon PersonIcon CheckboxIcon CalendarNowIcon CalendarTomorrowIcon CalendarYesterdayIcon BlockEmbedIcon TemplateIcon HTMLEmbedIcon YoutubeIcon]] + ["/components/Icons/Icons" :refer [TimeNowIcon PersonIcon CheckboxIcon CalendarNowIcon CalendarTomorrowIcon CalendarYesterdayIcon BlockEmbedIcon TemplateIcon HTMLEmbedIcon YoutubeIcon ArrowRightOnBoxIcon]] [athens.common-db :as common-db] [athens.common.utils :as common.utils] [athens.dates :as dates] @@ -101,7 +101,8 @@ ["YouTube Embed" YoutubeIcon "{{[[youtube]]: }}" nil 2] ["iframe Embed" HTMLEmbedIcon "{{iframe: }}" nil 2] ["Block Embed" BlockEmbedIcon "{{[[embed]]: (())}}" nil 4] - ["Template" TemplateIcon ";;" nil nil]] + ["Template" TemplateIcon ";;" nil nil] + ["Add reference to page" ArrowRightOnBoxIcon "#" nil nil]] @(subscribe [:db-picker/remote-db?]) (conj (let [username (:username @(rf/subscribe [:presence/current-user]))] [(str "Me (" username ")") PersonIcon (fn [] (str "[[" username "]]")) nil nil])))) @@ -140,7 +141,7 @@ :page #"(?s).*\[\[" :hashtag #"(?s).*#" :template #"(?s).*;;" - :add-to #"(?s).*\+" + :add-to #"(?s).*#" :slash #"(?s).*/") find (re-find regex head) query-start-idx (count find) @@ -213,6 +214,11 @@ (swap! state assoc :search/type :template :search/query "" + :search/results [])) + (when (= caption "Add reference to page") + (swap! state assoc + :search/type :add-to + :search/query "" :search/results []))))) @@ -316,12 +322,12 @@ ([state target expansion] (let [{:keys [start head]} (destruct-target target) - start-idx (count (re-find #"(?s).*\+" head))] + start-idx (count (re-find #"(?s).*#" head))] (if (nil? expansion) (swap! state assoc :search/type nil) (do - (set-selection target start-idx start) - (replace-selection-with (str "[[" expansion "]]")) + (set-selection target (dec start-idx) start) + (replace-selection-with "") (swap! state assoc :search/type nil) (dispatch [:add-to (:string/local @state) (:block/uid @state) expansion])))))) @@ -782,11 +788,9 @@ ;; slash: close dropdown (and (= "/" look-behind-char) (= type :slash)) (swap! state assoc :search/type nil) ;; hashtag: close dropdown - (and (= "#" look-behind-char) (= type :hashtag)) (swap! state assoc :search/type nil) + (and (= "#" look-behind-char) (#{:hashtag :add-to} type)) (swap! state assoc :search/type nil) ;; semicolon: close dropdown (and (= ";" look-behind-char) (= type :template)) (swap! state assoc :search/type nil) - ;; plus: close dropdown - (and (= "+" look-behind-char) (= type :at)) (swap! state assoc :search/type nil) ;; dropdown is open: update query type (update-query state head "" type)))) @@ -828,11 +832,6 @@ :search/query "" :search/type :template :search/results []) - (and (= key "+") (nil? type)) (swap! state assoc - :search/index 0 - :search/query "" - :search/type :add-to - :search/results []) type (update-query state head key type))))