mirror of https://github.com/logseq/logseq
enhance: auto-complete for property values
parent
5d7925115d
commit
7b74117d85
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -588,7 +588,6 @@
|
|||
|
||||
(defn set-editor-action!
|
||||
[value]
|
||||
(js/console.trace)
|
||||
(set-state! :editor/action value))
|
||||
|
||||
(defn set-editor-action-data!
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue