enhance: auto-complete for property values

pull/5935/head
Tienson Qin 2022-07-05 08:05:09 +08:00
parent 5d7925115d
commit 7b74117d85
9 changed files with 142 additions and 47 deletions

View File

@ -333,19 +333,19 @@
(+ current-pos i)))
current-pos)
orig-prefix (subs edit-content 0 current-pos)
space? (when (and last-pattern orig-prefix)
(let [s (when-let [last-index (string/last-index-of orig-prefix last-pattern)]
(gp-util/safe-subs orig-prefix 0 last-index))]
(not
(or
(and s
(string/ends-with? s "(")
(or (string/starts-with? last-pattern "((")
(string/starts-with? last-pattern "[[")))
(and s (string/starts-with? s "{{embed"))))))
space? (if (and space? (string/starts-with? last-pattern "#[["))
false
space?)
space? (let [space? (when (and last-pattern orig-prefix)
(let [s (when-let [last-index (string/last-index-of orig-prefix last-pattern)]
(gp-util/safe-subs orig-prefix 0 last-index))]
(not
(or
(and s
(string/ends-with? s "(")
(or (string/starts-with? last-pattern "((")
(string/starts-with? last-pattern "[[")))
(and s (string/starts-with? s "{{embed"))))))]
(if (and space? (string/starts-with? last-pattern "#[["))
false
space?))
prefix (cond
(and backward-truncate-number (integer? backward-truncate-number))
(str (gp-util/safe-subs orig-prefix 0 (- (count orig-prefix) backward-truncate-number))

View File

@ -421,7 +421,9 @@
[config page-name-in-block page-name redirect-page-name page-entity contents-page? children html-export? label]
(let [tag? (:tag? config)]
[:a
{:class (if tag? "tag" "page-ref")
{:class (cond-> (if tag? "tag" "page-ref")
(:property? config)
(str " page-property-key"))
:data-ref page-name
:on-mouse-down
(fn [e]
@ -1805,9 +1807,7 @@
[config block k v]
(let [date (and (= k :date) (date/get-locale-string (str v)))]
[:div
[:a.page-property-key
{:href (rfe/href :page {:name (name k)})}
(name k)]
(page-cp (assoc config :property? true) {:block/name (name k)})
[:span.mr-1 ":"]
(cond
(int? v)

View File

@ -237,22 +237,47 @@
(when input
(let [current-pos (cursor/pos input)
edit-content (state/sub [:editor/content id])
q (or
(when (>= (count edit-content) current-pos)
(subs edit-content pos current-pos))
"")
q (:searching-property (editor-handler/get-searching-property input))
matched-properties (editor-handler/get-matched-properties q)
q-property (string/replace (string/lower-case q) #"\s+" "-")
non-exist-handler (fn [_state]
((editor-handler/property-on-chosen-handler id q) nil))]
((editor-handler/property-on-chosen-handler id q-property) nil))]
(ui/auto-complete
matched-properties
{:on-chosen (editor-handler/property-on-chosen-handler id q)
{:on-chosen (editor-handler/property-on-chosen-handler id q-property)
:on-enter non-exist-handler
:empty-placeholder [:div.px-4.py-2.text-sm (str "Create a new property: " q)]
:empty-placeholder [:div.px-4.py-2.text-sm (str "Create a new property: " q-property)]
:header [:div.px-4.py-2.text-sm.font-medium "Matched properties: "]
:item-render (fn [property] property)
:class "black"})))))
(rum/defc property-value-search < rum/reactive
{:will-unmount (fn [state] (reset! editor-handler/*selected-text nil) state)}
[id]
(let [pos (:pos (:pos (state/get-editor-action-data)))
property (:property (state/get-editor-action-data))
input (gdom/getElement id)]
(when (and input
(not (string/blank? property)))
(let [current-pos (cursor/pos input)
edit-content (state/sub [:editor/content id])
start-idx (string/last-index-of (subs edit-content 0 current-pos) "::")
q (or
(when (>= current-pos (+ start-idx 2))
(subs edit-content (+ start-idx 2) current-pos))
"")
matched-values (editor-handler/get-matched-property-values property q)
non-exist-handler (fn [_state]
((editor-handler/property-value-on-chosen-handler id q) nil))]
(ui/auto-complete
matched-values
{:on-chosen (editor-handler/property-value-on-chosen-handler id q)
:on-enter non-exist-handler
:empty-placeholder [:div.px-4.py-2.text-sm (str "Create a new property value: " q)]
:header [:div.px-4.py-2.text-sm.font-medium "Matched property values: "]
:item-render (fn [property-value] property-value)
:class "black"})))))
(rum/defcs input < rum/reactive
(rum/local {} ::input-value)
(mixins/event-mixin
@ -515,6 +540,8 @@
(= :property-search action)
(animated-modal "property-search" (property-search id) true)
(= :property-value-search action)
(animated-modal "property-value-search" (property-value-search id) true)
(= :datepicker action)
(animated-modal "date-picker" (datetime-comp/date-picker id format nil) false)

View File

@ -1348,14 +1348,32 @@
:where
[_ :block/properties ?p]]
(conn/get-db))
properties (remove (fn [m] (or (empty? m)
(and (= 1 (count m))
(= :id (first (keys m)))))) properties)]
properties (remove (fn [m] (empty? m)) properties)]
(->> (map keys properties)
(apply concat)
distinct
(remove #{:id})
sort)))
(defn get-property-values
[property]
(let [pred (fn [_db properties]
(get properties property))]
(->>
(d/q
'[:find [?property-val ...]
:in $ ?pred
:where
[_ :block/properties ?p]
[(?pred $ ?p) ?property-val]]
(conn/get-db)
pred)
(map (fn [x] (if (coll? x) x [x])))
(apply concat)
(remove string/blank?)
(distinct)
(sort))))
(defn get-template-by-name
[name]
(when (string? name)

View File

@ -1620,6 +1620,10 @@
[q]
(search/property-search q))
(defn get-matched-property-values
[property q]
(search/property-value-search property q))
(defn get-matched-commands
[input]
(try
@ -1848,6 +1852,15 @@
(and (= last-input-char last-prev-input-char commands/colon)
(or (nil? prev-prev-input-char)
(= prev-prev-input-char "\n")))
(do
(cursor/move-cursor-backward input 2)
(state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})
(state/set-editor-show-property-search! true))
(and
(not= :property-search (state/get-editor-action))
(or (wrapped-by? input "" "::")
(wrapped-by? input "\n" "::")))
(do
(state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})
(state/set-editor-show-property-search! true))
@ -2054,17 +2067,39 @@
(insert-template! element-id db-id
{:replace-empty-target? true})))
(defn get-searching-property
[input]
(let [value (.-value input)
pos (util/get-selection-start input)
postfix (subs value pos)
end-index (when-let [idx (string/index-of postfix "::")]
(+ (max 0 (count (subs value 0 pos))) idx))
start-index (or (when-let [p (string/last-index-of (subs value 0 pos) "\n")]
(inc p))
0)]
{:end-index end-index
:searching-property (when (and start-index end-index (>= end-index start-index))
(subs value start-index end-index))}))
(defn property-on-chosen-handler
[element-id q]
(fn [property]
(when-let [input (gdom/getElement element-id)]
(let [value (.-value input)
pos (util/get-selection-start input)
last-index (string/last-index-of (subs value 0 pos) "::")
last-pattern (subs value last-index pos)]
(commands/insert! element-id (str (or property q) ":: ")
{:last-pattern last-pattern})
(state/clear-editor-action!)))))
(let [{:keys [end-index searching-property]} (get-searching-property input)]
(cursor/move-cursor-to input (+ end-index 2))
(commands/insert! element-id (str (or property q) "::")
{:last-pattern (str searching-property "::")})
(state/set-editor-action! :property-value-search)
(state/set-editor-action-data! {:property (or property q)
:pos (cursor/pos input)})))))
(defn property-value-on-chosen-handler
[element-id q]
(fn [property-value]
(when-let [input (gdom/getElement element-id)]
(commands/insert! element-id (or property-value q)
{:last-pattern q}))
(state/clear-editor-action!)))
(defn parent-is-page?
[{{:block/keys [parent page]} :data :as node}]

View File

@ -242,7 +242,7 @@
(defn- replace-property-ref!
[content old-name new-name]
(let [new-name (keyword (string/replace (string/lower-case new-name) #"\s+" "_"))
(let [new-name (keyword (string/replace (string/lower-case new-name) #"\s+" "-"))
old-property (str old-name "::")
new-property (str (name new-name) "::")]
(util/replace-ignore-case content old-property new-property)))
@ -274,7 +274,7 @@
(replace-old-page! f old-name new-name))
(and (keyword f) (= (name f) old-name))
(keyword (string/replace (string/lower-case new-name) #"\s+" "_"))
(keyword (string/replace (string/lower-case new-name) #"\s+" "-"))
:else
f))
@ -380,6 +380,7 @@
{:block/uuid uuid
:block/content content
:block/properties properties
:block/properties-order (map first properties)
:block/refs (rename-update-block-refs! (:block/refs block) (:db/id page) (:db/id to-page))
:block/path-refs (rename-update-block-refs! (:block/path-refs block) (:db/id page) (:db/id to-page))})))) blocks)
(remove nil?))]
@ -568,7 +569,8 @@
(rename-namespace-pages! repo old-name new-name))
(rename-nested-pages old-name new-name))
(when (string/blank? new-name)
(notification/show! "Please use a valid name, empty name is not allowed!" :error)))))
(notification/show! "Please use a valid name, empty name is not allowed!" :error)))
(ui-handler/re-render-root!)))
(defn- split-col-by-element
[col element]

View File

@ -172,7 +172,19 @@
(if (string/blank? q)
properties
(let [result (fuzzy-search properties q :limit limit)]
(vec result)))))))
(vec result)))))))
(defn property-value-search
([property q]
(property-value-search property q 10))
([property q limit]
(let [q (clean-str q)
result (db-model/get-property-values (keyword property))]
(when (seq result)
(if (string/blank? q)
result
(let [result (fuzzy-search result q :limit limit)]
(vec result)))))))
(defn sync-search-indice!
[repo tx-report]

View File

@ -588,7 +588,6 @@
(defn set-editor-action!
[value]
(js/console.trace)
(set-state! :editor/action value))
(defn set-editor-action-data!

View File

@ -86,19 +86,21 @@
(defn get-string-all-indexes
"Get all indexes of `value` in the string `s`."
[s value]
(loop [acc []
i 0]
(if-let [i (string/index-of s value i)]
(recur (conj acc i) (+ i (count value)))
acc)))
[s value before?]
(if (= value "")
(if before? [0] [(dec (count s))])
(loop [acc []
i 0]
(if-let [i (string/index-of s value i)]
(recur (conj acc i) (+ i (count value)))
acc))))
(defn wrapped-by?
"`pos` must be wrapped by `before` and `and` in string `value`, e.g. ((a|b))"
[value pos before end]
(let [before-matches (->> (get-string-all-indexes value before)
(let [before-matches (->> (get-string-all-indexes value before true)
(map (fn [i] [i :before])))
end-matches (->> (get-string-all-indexes value end)
end-matches (->> (get-string-all-indexes value end false)
(map (fn [i] [i :end])))
indexes (sort-by first (concat before-matches end-matches [[pos :between]]))
ks (map second indexes)