Merge remote-tracking branch 'upstream/master' into whiteboards

This commit is contained in:
Peng Xiao
2022-08-15 22:31:08 +08:00
22 changed files with 696 additions and 335 deletions

View File

@@ -2404,7 +2404,6 @@
(when (and
(state/in-selection-mode?)
(non-dragging? e))
(util/stop e)
(editor-handler/highlight-selection-area! block-id))))
(defn- block-mouse-leave
@@ -2463,7 +2462,9 @@
*navigating-block (get state ::navigating-block)
navigating-block (rum/react *navigating-block)
navigated? (and (not= (:block/uuid block) navigating-block) navigating-block)
block (if (or navigated? custom-query?)
block (if (or navigated?
custom-query?
(and ref? (:block/uuid config)))
(let [block (db/pull [:block/uuid navigating-block])
blocks (db/get-paginated-blocks repo (:db/id block)
{:scoped-block-id (:db/id block)})
@@ -2508,8 +2509,7 @@
edit? (state/sub [:editor/editing? edit-input-id])
card? (string/includes? data-refs-self "\"card\"")
review-cards? (:review-cards? config)
selected-blocks (set (state/get-selection-block-ids))
selected? (contains? selected-blocks uuid)]
selected? (state/sub-block-selected? uuid)]
[:div.ls-block
(cond->
{:id block-id
@@ -2848,7 +2848,8 @@
(let [dsl-query? (:dsl-query? config)
query-atom (:query-atom state)
repo (state/get-current-repo)
query-time (react/get-query-time query)
query-time (or (react/get-query-time query)
(react/get-query-time q))
view-fn (if (keyword? view) (state/sub [:config repo :query/views view]) view)
current-block-uuid (or (:block/uuid (:block config))
(:block/uuid config))
@@ -3331,7 +3332,7 @@
{:class (when doc-mode? "document-mode")}
(lazy-blocks config blocks' flat-blocks)]))))
(rum/defcs breadcrumb-with-container < rum/reactive
(rum/defcs breadcrumb-with-container < rum/reactive db-mixins/query
{:init (fn [state]
(let [first-block (ffirst (:rum/args state))]
(assoc state

View File

@@ -359,7 +359,7 @@
(block-ref-custom-context-menu-content block block-ref))
(state/set-state! :block-ref/context nil))
(state/selection?)
(and (state/selection?) (not (d/has-class? target "bullet")))
(common-handler/show-custom-context-menu!
e
(custom-context-menu-content))

View File

@@ -302,8 +302,12 @@
(let [[_id on-submit] (:rum/args state)
command (:command (first input-option))]
(on-submit command @input-value))
(reset! input-value nil))))})))
[state _id on-submit]
(reset! input-value nil))))
;; escape
27 (fn [_state _e]
(let [[id _on-submit on-cancel] (:rum/args state)]
(on-cancel id)))})))
[state _id on-submit _on-cancel]
(when (= :input (state/sub :editor/action))
(when-let [action-data (state/sub :editor/action-data)]
(let [{:keys [pos options]} action-data
@@ -335,7 +339,7 @@
(on-submit command @input-value pos)))]))))))
(rum/defc absolute-modal < rum/static
[cp set-default-width? {:keys [top left rect]}]
[cp modal-name set-default-width? {:keys [top left rect]}]
(let [max-height 370
max-width 300
offset-top 24
@@ -380,6 +384,7 @@
{:left (if (or (nil? y-diff) (and y-diff (= y-diff 0))) left 0)})))]
[:div.absolute.rounded-md.shadow-lg.absolute-modal
{:ref *el
:data-modal-name modal-name
:class (if y-overflow-vh? "is-overflow-vh-y" "")
:on-mouse-down (fn [e]
(.stopPropagation e))
@@ -387,13 +392,13 @@
cp]))
(rum/defc transition-cp < rum/reactive
[cp set-default-width?]
[cp modal-name set-default-width?]
(when-let [pos (:pos (state/sub :editor/action-data))]
(ui/css-transition
{:class-names "fade"
:timeout {:enter 500
:exit 300}}
(absolute-modal cp set-default-width? pos))))
(absolute-modal cp modal-name set-default-width? pos))))
(rum/defc image-uploader < rum/reactive
[id format]
@@ -412,6 +417,7 @@
[:div.flex.flex-row.align-center.rounded-md.shadow-sm.bg-base-2.px-1.py-1
(ui/loading
(util/format "Uploading %s%" (util/format "%2d" processing)))]
"upload-file"
false)))])
(defn- set-up-key-down!
@@ -422,11 +428,11 @@
{:not-matched-handler (editor-handler/keydown-not-matched-handler format)}))
(defn- set-up-key-up!
[state input input-id search-timeout]
[state input input-id]
(mixins/on-key-up
state
{}
(editor-handler/keyup-handler state input input-id search-timeout)))
(editor-handler/keyup-handler state input input-id)))
(def search-timeout (atom nil))
@@ -436,7 +442,7 @@
input-id id
input (gdom/getElement input-id)]
(set-up-key-down! state format)
(set-up-key-up! state input input-id search-timeout)))
(set-up-key-up! state input input-id)))
(def starts-with? clojure.string/starts-with?)
@@ -510,10 +516,10 @@
(mock-textarea content)))
(rum/defc animated-modal < rum/reactive
[key component set-default-width?]
[modal-name component set-default-width?]
(when-let [pos (:pos (state/get-editor-action-data))]
(ui/css-transition
{:key key
{:key modal-name
:class-names {:enter "origin-top-left opacity-0 transform scale-95"
:enter-done "origin-top-left transition opacity-100 transform scale-100"
:exit "origin-top-left transition opacity-0 transform scale-95"}
@@ -522,6 +528,7 @@
(fn [_]
(absolute-modal
component
modal-name
set-default-width?
pos)))))
@@ -557,7 +564,9 @@
(= :input action)
(animated-modal "input" (input id
(fn [command m]
(editor-handler/handle-command-input command id format m)))
(editor-handler/handle-command-input command id format m))
(fn []
(editor-handler/handle-command-input-close id)))
true)
(= :zotero action)

View File

@@ -19,12 +19,12 @@
(rum/defc blocks-cp < rum/reactive db-mixins/query
{}
[repo page _format]
[repo page]
(when-let [page-e (db/pull [:block/name (util/page-name-sanity-lc page)])]
(page/page-blocks-cp repo page-e {})))
(rum/defc journal-cp < rum/reactive
[[title format]]
[title]
(let [;; Don't edit the journal title
page (string/lower-case title)
repo (state/sub :git/current-repo)
@@ -56,9 +56,9 @@
(gp-util/capitalize-all title)]]
(if today?
(blocks-cp repo page format)
(blocks-cp repo page)
(ui/lazy-visible
(fn [] (blocks-cp repo page format))
(fn [] (blocks-cp repo page))
{:debug-id (str "journal-blocks " page)}))
{})
@@ -77,9 +77,9 @@
[:div#journals
(ui/infinite-list
"main-content-container"
(for [{:block/keys [name format]} latest-journals]
(for [{:block/keys [name]} latest-journals]
[:div.journal-item.content {:key name}
(journal-cp [name format])])
(journal-cp name)])
{:has-more (page-handler/has-more-journals?)
:more-class "text-4xl"
:on-top-reached page-handler/create-today-journal!

View File

@@ -147,7 +147,7 @@
:init-collapsed (fn [collapsed-atom]
(reset! *collapsed? collapsed-atom))})))
(rum/defcs references* < rum/reactive
(rum/defcs references* < rum/reactive db-mixins/query
{:init (fn [state]
(let [page-name (first (:rum/args state))
filters (when page-name

View File

@@ -378,6 +378,15 @@
(get-file-path repo
(str app-name "/" export-css-file)))))
(defn expand-relative-assets-path
;; ../assets/xxx -> {assets|file}://{current-graph-root-path}/xxx
[source]
(when-let [protocol (and (string? source)
(not (string/blank? source))
(if (util/electron?) "assets" "file"))]
(string/replace
source "../assets" (util/format "%s://%s/assets" protocol (get-repo-dir (state/get-current-repo))))))
(defn get-custom-js-path
([]

View File

@@ -356,28 +356,36 @@
([blocks parent]
(sort-by-left blocks parent {:check? true}))
([blocks parent {:keys [check?]}]
(when check?
(when (not= (count blocks) (count (set (map :block/left blocks))))
(let [duplicates (->> (map (comp :db/id :block/left) blocks)
frequencies
(filter (fn [[_k v]] (> v 1)))
(map (fn [[k _v]]
(let [left (db-utils/pull k)]
{:left left
:duplicates (->>
(filter (fn [block]
(= k (:db/id (:block/left block))))
blocks)
(map #(select-keys % [:db/id :block/level :block/content :block/file])))}))))]
#_(util/pprint duplicates)))
(assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node"))
(let [blocks (util/distinct-by :db/id blocks)]
(when check?
(when (not= (count blocks) (count (set (map :block/left blocks))))
(let [duplicates (->> (map (comp :db/id :block/left) blocks)
frequencies
(filter (fn [[_k v]] (> v 1)))
(map (fn [[k _v]]
(let [left (db-utils/pull k)]
{:left left
:duplicates (->>
(filter (fn [block]
(= k (:db/id (:block/left block))))
blocks)
(map #(select-keys % [:db/id :block/level :block/content :block/file])))}))))]
(util/pprint duplicates)))
(assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node"))
(let [left->blocks (reduce (fn [acc b] (assoc acc (:db/id (:block/left b)) b)) {} blocks)]
(loop [block parent
result []]
(if-let [next (get left->blocks (:db/id block))]
(recur next (conj result next))
(vec result))))))
(let [left->blocks (reduce (fn [acc b] (assoc acc (:db/id (:block/left b)) b)) {} blocks)]
(loop [block parent
result []]
(if-let [next (get left->blocks (:db/id block))]
(recur next (conj result next))
(vec result)))))))
(defn try-sort-by-left
[blocks parent]
(let [result' (sort-by-left blocks parent {:check? false})]
(if (= (count result') (count blocks))
result'
blocks)))
(defn sort-by-left-recursive
[form]
@@ -450,6 +458,11 @@
parent-sibling
(get-next-outdented-block db (:db/id parent))))))
(defn top-block?
[block]
(= (:db/id (:block/parent block))
(:db/id (:block/page block))))
(defn get-block-parent
([block-id]
(get-block-parent (state/get-current-repo) block-id))
@@ -458,11 +471,6 @@
(when-let [block (d/entity db [:block/uuid block-id])]
(:block/parent block)))))
(defn top-block?
[block]
(= (:db/id (:block/parent block))
(:db/id (:block/page block))))
;; non recursive query
(defn get-block-parents
([repo block-id]
@@ -477,13 +485,6 @@
(recur (:block/uuid parent) (conj parents parent) (inc d))
parents)))))
(comment
(defn get-immediate-children-v2
[repo block-id]
(d/pull (conn/get-db repo)
'[:block/_parent]
[:block/uuid block-id])))
;; Use built-in recursive
(defn get-block-parents-v2
[repo block-id]
@@ -859,17 +860,14 @@
(defn get-block-children-ids
[repo block-uuid]
(when-let [db (conn/get-db repo)]
(let [eid (:db/id (db-utils/entity repo [:block/uuid block-uuid]))]
(->> (d/q
'[:find ?id
:in $ ?p %
:where
(child ?p ?c)
[?c :block/uuid ?id]]
db
eid
rules)
(apply concat)))))
(when-let [eid (:db/id (db-utils/entity repo [:block/uuid block-uuid]))]
(let [get-children-ids (fn get-children-ids [eid]
(mapcat
(fn [datom]
(let [id (first datom)]
(cons (:block/uuid (d/entity db id)) (get-children-ids id))))
(d/datoms db :avet :block/parent eid)))]
(get-children-ids eid)))))
(defn get-block-immediate-children
"Doesn't include nested children."
@@ -1173,21 +1171,19 @@
(get-page-referenced-blocks-full (state/get-current-repo) page options))
([repo page options]
(when repo
(when (conn/get-db repo)
(when-let [db (conn/get-db repo)]
(let [page-id (:db/id (db-utils/entity [:block/name (util/safe-page-name-sanity-lc page)]))
pages (page-alias-set repo page)
aliases (set/difference pages #{page-id})]
(->>
(react/q repo
[:frontend.db.react/page<-blocks-or-block<-blocks page-id]
{}
'[:find [(pull ?block ?block-attrs) ...]
:in $ [?ref-page ...] ?block-attrs
:where
[?block :block/path-refs ?ref-page]]
pages
(butlast block-attrs))
react
(d/q
'[:find [(pull ?block ?block-attrs) ...]
:in $ [?ref-page ...] ?block-attrs
:where
[?block :block/path-refs ?ref-page]]
db
pages
(butlast block-attrs))
(remove (fn [block] (= page-id (:db/id (:block/page block)))))
db-utils/group-by-page
(map (fn [[k blocks]]
@@ -1209,17 +1205,16 @@
aliases (set/difference pages #{page-id})]
(->>
(react/q repo
[:frontend.db.react/page<-blocks-or-block<-blocks page-id]
{:use-cache? false
:query-fn (fn []
(let [entities (mapcat (fn [id]
(:block/_path-refs (db-utils/entity id))) pages)
blocks (map (fn [e] {:block/parent (:block/parent e)
:block/left (:block/left e)
:block/page (:block/page e)}) entities)]
{:entities entities
:blocks blocks}))}
nil)
[:frontend.db.react/refs page-id]
{:query-fn (fn []
(let [entities (mapcat (fn [id]
(:block/_path-refs (db-utils/entity id))) pages)
blocks (map (fn [e] {:block/parent (:block/parent e)
:block/left (:block/left e)
:block/page (:block/page e)}) entities)]
{:entities entities
:blocks blocks}))}
nil)
react
:entities
(remove (fn [block] (= page-id (:db/id (:block/page block)))))
@@ -1239,16 +1234,15 @@
page? (:block/name block)
result (if page?
(let [pages (page-alias-set repo (:block/name block))]
(d/q
'[:find [?block ...]
:in $ [?ref-page ...] ?id
:where
[?block :block/refs ?ref-page]
[?block :block/page ?p]
[(not= ?p ?id)]]
(conn/get-db repo)
pages
id))
@(react/q repo [:frontend.db.react/refs-count id] {}
'[:find [?block ...]
:in $ [?ref-page ...] ?id
:where
[?block :block/refs ?ref-page]
[?block :block/page ?p]
[(not= ?p ?id)]]
pages
id))
(:block/_refs block))]
(count result))))
@@ -1312,8 +1306,6 @@
(sort-by-left-recursive)
db-utils/group-by-page)))))
;; TODO: Replace recursive queries with datoms index implementation
;; see https://github.com/tonsky/datascript/issues/130#issuecomment-169520434
(defn get-block-referenced-blocks
([block-uuid]
(get-block-referenced-blocks block-uuid {}))
@@ -1321,16 +1313,16 @@
(when-let [repo (state/get-current-repo)]
(when (conn/get-db repo)
(let [block (db-utils/entity [:block/uuid block-uuid])
query-result (->> (react/q repo [:frontend.db.react/page<-blocks-or-block<-blocks
query-result (->> (react/q repo [:frontend.db.react/refs
(:db/id block)]
{:use-cache? false}
'[:find [(pull ?ref-block ?block-attrs) ...]
:in $ ?block-uuid ?block-attrs
:where
[?block :block/uuid ?block-uuid]
[?ref-block :block/refs ?block]]
block-uuid
block-attrs)
{}
'[:find [(pull ?ref-block ?block-attrs) ...]
:in $ ?block-uuid ?block-attrs
:where
[?block :block/uuid ?block-uuid]
[?ref-block :block/refs ?block]]
block-uuid
block-attrs)
react
(sort-by-left-recursive))]
(db-utils/group-by-page query-result))))))

View File

@@ -24,38 +24,29 @@
;; get block&children react-query
(s/def ::block-and-children (s/tuple #(= ::block-and-children %) uuid?))
(s/def ::block-direct-children (s/tuple #(= ::block-direct-children %) uuid?))
;; ::journals
;; get journal-list react-query
(s/def ::journals (s/tuple #(= ::journals %)))
;; ::page->pages
;; get PAGES referenced by PAGE
(s/def ::page->pages (s/tuple #(= ::page->pages %) int?))
;; ::page<-pages
;; get PAGES referencing PAGE
(s/def ::page<-pages (s/tuple #(= ::page<-pages %) int?))
;; ::page<-blocks-or-block<-blocks
;; ::refs
;; get BLOCKS referencing PAGE or BLOCK
(s/def ::page<-blocks-or-block<-blocks
(s/tuple #(= ::page<-blocks-or-block<-blocks %) int?))
;; FIXME: this react-query has performance issues
(s/def ::page-unlinked-refs (s/tuple #(= ::page-unlinked-refs %) int?))
;; ::block<-block-ids
;; get BLOCK-IDS referencing BLOCK
(s/def ::block<-block-ids (s/tuple #(= ::block<-block-ids %) int?))
(s/def ::refs (s/tuple #(= ::refs %) int?))
;; ::refs-count
;; get refs count
(s/def ::refs-count int?)
;; custom react-query
(s/def ::custom any?)
(s/def ::react-query-keys (s/or :block ::block
:page-blocks ::page-blocks
:block-and-children ::block-and-children
:block-direct-children ::block-direct-children
:journals ::journals
:page->pages ::page->pages
:page<-pages ::page<-pages
:page<-blocks-or-block<-blocks ::page<-blocks-or-block<-blocks
:page-unlinked-refs ::page-unlinked-refs
:block<-block-ids ::block<-block-ids
:refs ::refs
:refs-count ::refs-count
:custom ::custom))
(s/def ::affected-keys (s/coll-of ::react-query-keys))
@@ -125,13 +116,14 @@
(defn add-q!
[k query time inputs result-atom transform-fn query-fn inputs-fn]
(swap! query-state assoc k {:query query
:query-time time
:inputs inputs
:result result-atom
:transform-fn transform-fn
:query-fn query-fn
:inputs-fn inputs-fn})
(let [time' (int (util/safe-parse-float time))]
(swap! query-state assoc k {:query query
:query-time time'
:inputs inputs
:result result-atom
:transform-fn transform-fn
:query-fn query-fn
:inputs-fn inputs-fn}))
result-atom)
(defn remove-q!
@@ -141,14 +133,16 @@
(defn add-query-component!
[key component]
(when (and key component)
(swap! query-components assoc component key)))
(swap! query-components update component (fn [col] (set (conj col key))))))
(defn remove-query-component!
[component]
(when-let [query (get @query-components component)]
(let [matched-queries (filter #(= query %) (vals @query-components))]
(when (= 1 (count matched-queries))
(remove-q! query))))
(when-let [queries (get @query-components component)]
(let [all-queries (apply concat (vals @query-components))]
(doseq [query queries]
(let [matched-queries (filter #(= query %) all-queries)]
(when (= 1 (count matched-queries))
(remove-q! query))))))
(swap! query-components dissoc component))
;; TODO: rename :custom to :query/custom
@@ -220,64 +214,80 @@
(let [page-name (util/page-name-sanity-lc page)]
(db-utils/entity [:block/name page-name])))))
(defn- get-block-parents
[db id]
(let [get-parent (fn [id] (:db/id (:block/parent (d/entity db id))))]
(loop [result [id]
id id]
(if-let [parent (get-parent id)]
(recur (conj result parent) parent)
result))))
(defn- get-blocks-parents-from-both-dbs
[db-after db-before block-entities]
(let [current-db-parent-ids (->> (set (keep :block/parent block-entities))
(mapcat (fn [parent]
(get-block-parents db-after (:db/id parent)))))
before-db-parent-ids (->> (map :db/id block-entities)
(mapcat (fn [id]
(get-block-parents db-before id))))]
(set (concat current-db-parent-ids before-db-parent-ids))))
(defn get-affected-queries-keys
"Get affected queries through transaction datoms."
[{:keys [tx-data db-before]}]
[{:keys [tx-data db-before db-after]}]
{:post [(s/valid? ::affected-keys %)]}
(let [blocks (->> (filter (fn [datom] (contains? #{:block/left :block/parent :block/page} (:a datom))) tx-data)
(map :v)
(distinct))
refs (->> (filter (fn [datom] (= :block/refs (:a datom))) tx-data)
refs (->> (filter (fn [datom] (contains? #{:block/refs :block/path-refs} (:a datom))) tx-data)
(map :v)
(distinct))
other-blocks (->> (filter (fn [datom] (= "block" (namespace (:a datom)))) tx-data)
(map :e))
blocks (-> (concat blocks other-blocks) distinct)
block-entities (keep (fn [block-id]
(let [block-id (if (and (string? block-id) (util/uuid-string? block-id))
[:block/uuid block-id]
block-id)]
(db-utils/entity block-id))) blocks)
affected-keys (concat
(mapcat
(fn [block-id]
(let [block-id (if (and (string? block-id) (util/uuid-string? block-id))
[:block/uuid block-id]
block-id)]
(when-let [block (db-utils/entity block-id)]
(let [page-id (or
(when (:block/name block) (:db/id block))
(:db/id (:block/page block)))
blocks [[::block (:db/id block)]]
others (when page-id
(let [db-after-parent-uuid (:block/uuid (:block/parent block))
db-before-parent-uuid (:block/uuid (:block/parent (d/entity db-before
[:block/uuid (:block/uuid block)])))]
[[::page-blocks page-id]
[::page->pages page-id]
[::block-direct-children db-after-parent-uuid]
(when (and db-before-parent-uuid
(not= db-before-parent-uuid db-after-parent-uuid))
[::block-direct-children db-before-parent-uuid])]))]
(concat blocks others)))))
blocks)
(fn [block]
(let [page-id (or
(when (:block/name block) (:db/id block))
(:db/id (:block/page block)))
blocks [[::block (:db/id block)]]
path-refs (:block/path-refs block)
path-refs' (mapcat (fn [ref]
[
;; [::refs-count (:db/id ref)]
[::refs (:db/id ref)]]) path-refs)
page-blocks (when page-id
[[::page-blocks page-id]])]
(concat blocks page-blocks path-refs')))
block-entities)
(mapcat
(fn [ref]
[
;; [::refs-count (:db/id entity)]
[::refs ref]])
refs)
(when-let [current-page-id (:db/id (get-current-page))]
[[::page->pages current-page-id]
[::page<-pages current-page-id]])
(map (fn [ref]
(let [entity (db-utils/entity ref)]
(if (:block/name entity) ; page
[::page-blocks ref]
[::page-blocks (:db/id (:block/page entity))])))
refs))
others (->>
(keys @query-state)
(filter (fn [ks]
(contains? #{::block-and-children
::page<-blocks-or-block<-blocks}
(second ks))))
(map (fn [v] (vec (rest v)))))]
[[::page<-pages current-page-id]]))
parent-ids (get-blocks-parents-from-both-dbs db-after db-before block-entities)
block-children-keys (->>
(keys @query-state)
(keep (fn [ks]
(when (and (= ::block-and-children (second ks))
(contains? parent-ids (last ks)))
(vec (rest ks))))))]
(->>
(util/concat-without-nil
affected-keys
others)
block-children-keys)
set)))
(defn- execute-query!
@@ -314,8 +324,6 @@
(when-let [outliner-op (:outliner-op tx-meta)]
(not (or
(contains? #{:collapse-expand-blocks :delete-blocks} outliner-op)
;; ignore move up/down since it doesn't affect the refs for any blocks
(contains? #{:move-blocks-up-down} (:move-op tx-meta))
(:undo? tx-meta) (:redo? tx-meta)))))
(defn refresh!
@@ -335,16 +343,18 @@
custom?
kv?))
(let [{:keys [query query-fn]} cache
query-or-refs? (state/edit-in-query-or-refs-component)]
(when (or query query-fn)
(try
(let [f #(execute-query! repo-url db k tx cache {:skip-query-time-check? query-or-refs?})]
;; Detects whether user is editing in a custom query, if so, execute the query immediately
(if (or query-or-refs? (not custom?))
(f)
(async/put! (state/get-reactive-custom-queries-chan) [f query])))
(catch js/Error e
(js/console.error e))))))))))))
{:keys [custom-query?]} (state/edit-in-query-or-refs-component)]
(util/profile
(str "refresh! " (rest k))
(when (or query query-fn)
(try
(let [f #(execute-query! repo-url db k tx cache {:skip-query-time-check? custom-query?})]
;; Detects whether user is editing in a custom query, if so, execute the query immediately
(if (and custom? (not custom-query?))
(async/put! (state/get-reactive-custom-queries-chan) [f query])
(f)))
(catch js/Error e
(js/console.error e)))))))))))))
(defn set-key-value
[repo-url key value]

View File

@@ -205,8 +205,8 @@
(defn clear-selection!
[]
(util/select-unhighlight! (dom/by-class "selected"))
(state/clear-selection!))
(state/clear-selection!)
(util/select-unhighlight! (dom/by-class "selected")))
(defn- text-range-by-lst-fst-line [content [direction pos]]
(case direction
@@ -1073,8 +1073,11 @@
(when-let [blocks (seq (get-selected-blocks))]
;; remove embeds, references and queries
(let [dom-blocks (remove (fn [block]
(or (= "true" (dom/attr block "data-transclude"))
(= "true" (dom/attr block "data-query")))) blocks)]
(or (= "true" (dom/attr block "data-transclude"))
(= "true" (dom/attr block "data-query")))) blocks)
dom-blocks (if (seq dom-blocks) dom-blocks
(remove (fn [block]
(= "true" (dom/attr block "data-transclude"))) blocks))]
(when (seq dom-blocks)
(let [repo (state/get-current-repo)
block-uuids (distinct (map #(uuid (dom/attr % "blockid")) dom-blocks))
@@ -1220,8 +1223,7 @@
(defn clear-last-selected-block!
[]
(let [block (state/drop-last-selection-block!)]
(util/select-unhighlight! [block])))
(state/drop-last-selection-block!))
(defn highlight-selection-area!
[end-block]
@@ -1236,18 +1238,18 @@
(defn- select-block-up-down
[direction]
(cond
;; when editing, quit editing and select current block
;; when editing, quit editing and select current block
(state/editing?)
(state/exit-editing-and-set-selected-blocks! [(gdom/getElement (state/get-editing-block-dom-id))])
;; when selection and one block selected, select next block
;; when selection and one block selected, select next block
(and (state/selection?) (== 1 (count (state/get-selection-blocks))))
(let [f (if (= :up direction) util/get-prev-block-non-collapsed util/get-next-block-non-collapsed-skip)
element (f (first (state/get-selection-blocks)))]
(when element
(state/conj-selection-block! element direction)))
;; if same direction, keep conj on same direction
;; if same direction, keep conj on same direction
(and (state/selection?) (= direction (state/get-selection-direction)))
(let [f (if (= :up direction) util/get-prev-block-non-collapsed util/get-next-block-non-collapsed-skip)
first-last (if (= :up direction) first last)
@@ -1255,7 +1257,7 @@
(when element
(state/conj-selection-block! element direction)))
;; if different direction, keep clear until one left
;; if different direction, keep clear until one left
(state/selection?)
(clear-last-selected-block!))
nil)
@@ -1734,6 +1736,13 @@
:markdown (util/format "![%s](%s)" label link)
:org (util/format "[[%s]]"))))
(defn handle-command-input-close [id]
(state/set-editor-show-input! nil)
(when-let [saved-cursor (state/get-editor-last-pos)]
(when-let [input (gdom/getElement id)]
(.focus input)
(cursor/move-cursor-to input saved-cursor))))
(defn handle-command-input [command id format m]
;; TODO: Add error handling for when user doesn't provide a required field.
;; (The current behavior is to just revert back to the editor.)
@@ -1757,41 +1766,24 @@
nil)
(state/set-editor-show-input! nil)
(when-let [saved-cursor (state/get-editor-last-pos)]
(when-let [input (gdom/getElement id)]
(.focus input)
(cursor/move-cursor-to input saved-cursor))))
(defn get-search-q
[]
(when-let [id (state/get-edit-input-id)]
(when-let [input (gdom/getElement id)]
(let [current-pos (cursor/pos input)
pos (state/get-editor-last-pos)
edit-content (or (state/sub [:editor/content id]) "")]
(or
@*selected-text
(gp-util/safe-subs edit-content pos current-pos))))))
(handle-command-input-close id))
(defn close-autocomplete-if-outside
[input]
(when (and input
(state/get-editor-action)
(not (wrapped-by? input page-ref/left-brackets page-ref/right-brackets)))
(when (get-search-q)
(let [value (gobj/get input "value")
pos (state/get-editor-last-pos)
current-pos (cursor/pos input)
between (gp-util/safe-subs value (min pos current-pos) (max pos current-pos))]
(when (and between
(or
(string/includes? between "[")
(string/includes? between "]")
(string/includes? between "(")
(string/includes? between ")")))
(state/clear-editor-action!))))))
(let [value (gobj/get input "value")
pos (state/get-editor-last-pos)
current-pos (cursor/pos input)
between (gp-util/safe-subs value (min pos current-pos) (max pos current-pos))]
(when (and between
(or
(string/includes? between "[")
(string/includes? between "]")
(string/includes? between "(")
(string/includes? between ")")))
(state/clear-editor-action!)))))
(defn resize-image!
[block-id metadata full_text size]
@@ -1821,7 +1813,7 @@
(reset! *auto-save-timeout
(js/setTimeout
(fn []
(when (state/input-idle? repo)
(when (state/input-idle? repo :diff 500)
(state/set-editor-op! :auto-save)
; don't auto-save for page's properties block
(save-current-block! {:skip-properties? true})
@@ -2816,7 +2808,7 @@
nil))))
(defn ^:large-vars/cleanup-todo keyup-handler
[_state input input-id search-timeout]
[_state input input-id]
(fn [e key-code]
(when-not (util/event-is-composing? e)
(let [current-pos (cursor/pos input)
@@ -2889,7 +2881,7 @@
(when (and (not editor-action) (not non-enter-processed?))
(cond
;; When you type text inside square brackets
(and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp"} k))
(and (not (contains? #{"ArrowDown" "ArrowLeft" "ArrowRight" "ArrowUp" "Escape"} k))
(wrapped-by? input page-ref/left-brackets page-ref/right-brackets))
(let [orig-pos (cursor/get-caret-pos input)
value (gobj/get input "value")
@@ -2937,11 +2929,11 @@
(state/set-editor-action-data! {:pos (cursor/get-caret-pos input)})
(state/set-editor-show-block-commands!))
(nil? @search-timeout)
(close-autocomplete-if-outside input)
:else
nil)))
(close-autocomplete-if-outside input)
(when-not (or (= k "Shift") is-processed?)
(state/set-last-key-code! {:key-code key-code
:code code

View File

@@ -1,6 +1,5 @@
(ns frontend.handler.editor.keyboards
(:require [dommy.core :as d]
[frontend.handler.editor :as editor-handler]
(:require [frontend.handler.editor :as editor-handler]
[frontend.mixins :as mixins]
[frontend.state :as state]
[goog.dom :as gdom]))
@@ -12,15 +11,26 @@
(mixins/hide-when-esc-or-outside
state
:on-hide
(fn [_state e event]
(let [target (.-target e)]
(if (d/has-class? target "bottom-action") ;; FIXME: not particular case
(.preventDefault e)
(let [{:keys [on-hide value]} (editor-handler/get-state)]
(when on-hide
(on-hide value event))
(when (contains? #{:esc :visibilitychange :click} event)
(state/clear-edit!))))))
(fn [_state _e event]
(cond
(contains?
#{:commands :block-commands
:page-search :page-search-hashtag :block-search :template-search
:property-search :property-value-search
:datepicker}
(state/get-editor-action))
(state/clear-editor-action!) ;; FIXME: This should probably be handled as a keydown handler in editor, but this handler intercepts Esc first
;; editor/input component handles Escape directly, so just prevent handling it here
(= :input (state/get-editor-action))
nil
:else
(let [{:keys [on-hide value]} (editor-handler/get-state)]
(when on-hide
(on-hide value event))
(when (contains? #{:esc :visibilitychange :click} event)
(state/clear-edit!)))))
:node (gdom/getElement id)
;; :visibilitychange? true
)))

View File

@@ -21,6 +21,7 @@
[e]
(util/stop e)
(state/set-editor-op! :undo)
(state/clear-editor-action!)
(editor/save-current-block!)
(let [{:keys [editor-cursor]} (undo-redo/undo)]
(restore-cursor! editor-cursor))
@@ -30,6 +31,7 @@
[e]
(util/stop e)
(state/set-editor-op! :redo)
(state/clear-editor-action!)
(let [{:keys [editor-cursor]} (undo-redo/redo)]
(restore-cursor! editor-cursor))
(state/set-editor-op! nil))

View File

@@ -125,7 +125,8 @@
[]
(when-let [style (or
(state/get-custom-css-link)
(db-model/get-custom-css)
(some-> (db-model/get-custom-css)
(config/expand-relative-assets-path))
;; (state/get-custom-css-link)
)]
(util/add-style! style)))

View File

@@ -1,7 +1,7 @@
(ns frontend.mixins
(:require [rum.core :as rum]
[goog.dom :as dom]
[frontend.util :refer [profile]]
[frontend.util :refer [profile] :as util]
[frontend.state :as state])
(:import [goog.events EventHandler]))
@@ -26,43 +26,21 @@
(detach state)
(dissoc state ::event-handler))})
;; (defn timeout-mixin
;; "The setTimeout mixin."
;; [name t f]
;; {:will-mount
;; (fn [state]
;; (assoc state name (util/set-timeout t f)))
;; :will-unmount
;; (fn [state]
;; (let [timeout (get state name)]
;; (util/clear-timeout timeout)
;; (dissoc state name)))})
;; (defn interval-mixin
;; "The setInterval mixin."
;; [name t f]
;; {:will-mount
;; (fn [state]
;; (assoc state name (util/set-interval t f)))
;; :will-unmount
;; (fn [state]
;; (when-let [interval (get state name)]
;; (util/clear-interval interval))
;; (dissoc state name))})
(defn hide-when-esc-or-outside
[state & {:keys [on-hide node visibilitychange? outside?]}]
(try
(let [dom-node (rum/dom-node state)]
(when-let [dom-node (or node dom-node)]
(or (false? outside?)
(listen state js/window "mousedown"
(fn [e]
(let [target (.. e -target)]
;; If the click target is outside of current node
(when (and (not (dom/contains dom-node target))
(not (.contains (.-classList target) "ignore-outside-event")))
(on-hide state e :click))))))
(let [click-fn (fn [e]
(let [target (.. e -target)]
;; If the click target is outside of current node
(when (and
(not (util/input? dom-node))
(not (dom/contains dom-node target))
(not (.contains (.-classList target) "ignore-outside-event")))
(on-hide state e :click))))]
(when-not (false? outside?)
(listen state js/window "mouseup" click-fn)))
(listen state js/window "keydown"
(fn [e]
(case (.-keyCode e)

View File

@@ -46,18 +46,21 @@
[repo page-db-id]
(let [page-block (db/pull repo '[*] page-db-id)
page-db-id (:db/id page-block)
whiteboard? (:block/whiteboard? page-block)
pull-keys (if whiteboard? whiteboard-blocks-pull-keys-with-persisted-ids '[*])
blocks (model/get-page-blocks-no-cache repo (:block/name page-block) {:pull-keys pull-keys})
blocks (if whiteboard? (map cleanup-whiteboard-block blocks) blocks)]
(when-not (and (= 1 (count blocks))
(string/blank? (:block/content (first blocks)))
(nil? (:block/file page-block)))
(let [tree (tree/blocks->vec-tree repo blocks (:block/name page-block))]
(if page-block
(file/save-tree! page-block (if whiteboard? blocks tree))
(js/console.error (str "can't find page id: " page-db-id)))))))
blocks-count (model/get-page-blocks-count repo page-db-id)]
(if (and (> blocks-count 500)
(not (state/input-idle? repo :diff 3000))) ; long page
(async/put! write-chan [repo page-db-id])
(let [whiteboard? (:block/whiteboard? page-block)
pull-keys (if whiteboard? whiteboard-blocks-pull-keys-with-persisted-ids '[*])
blocks (model/get-page-blocks-no-cache repo (:block/name page-block) {:pull-keys pull-keys})
blocks (if whiteboard? (map cleanup-whiteboard-block blocks) blocks)]
(when-not (and (= 1 (count blocks))
(string/blank? (:block/content (first blocks)))
(nil? (:block/file page-block)))
(let [tree (tree/blocks->vec-tree repo blocks (:block/name page-block))]
(if page-block
(file/save-tree! page-block (if whiteboard? blocks tree))
(js/console.error (str "can't find page id: " page-db-id)))))))))
(defn write-files!
[pages]

View File

@@ -23,7 +23,10 @@
(defn compute-block-path-refs
[tx-meta blocks]
(let [repo (state/get-current-repo)
blocks (remove :block/name blocks)]
blocks (remove :block/name blocks)
blocks (if (= (:outliner-op tx-meta) :insert-blocks)
(butlast blocks)
blocks)]
(when (:outliner-op tx-meta)
(when (react/path-refs-need-recalculated? tx-meta)
(let [*computed-ids (atom #{})]
@@ -61,7 +64,9 @@
(not (:compute-new-refs? tx-meta)))
(let [{:keys [pages blocks]} (ds-report/get-blocks-and-pages tx-report)
repo (state/get-current-repo)
refs-tx (set (compute-block-path-refs (:tx-meta tx-report) blocks))
refs-tx (util/profile
"Compute path refs: "
(set (compute-block-path-refs (:tx-meta tx-report) blocks)))
truncate-refs-tx (map (fn [m] [:db/retract (:db/id m) :block/path-refs]) refs-tx)
tx (util/concat-without-nil truncate-refs-tx refs-tx)
tx-report' (if (seq tx)

View File

@@ -66,8 +66,8 @@
root-block (assoc root-block :block/children result)]
[root-block])))))))
(defn- tree [flat-nodes root-id]
(let [children (group-by :block/parent flat-nodes)
(defn- tree [parent->children root]
(let [root-id (:db/id root)
nodes (fn nodes [parent-id level]
(mapv (fn [b]
(let [b' (assoc b :block/level (inc level))
@@ -75,8 +75,14 @@
(if (seq children)
(assoc b' :block/children children)
b')))
(get children {:db/id parent-id})))]
(nodes root-id 1)))
(let [parent {:db/id parent-id}]
(-> (get parent->children parent)
(model/try-sort-by-left parent)))))
children (nodes root-id 1)
root' (assoc root :block/level 1)]
(if (seq children)
(assoc root' :block/children children)
root')))
(defn non-consecutive-blocks->vec-tree
"`blocks` need to be in the same page."
@@ -84,26 +90,15 @@
(let [blocks (map (fn [e] {:db/id (:db/id e)
:block/uuid (:block/uuid e)
:block/parent {:db/id (:db/id (:block/parent e))}
:block/left {:db/id (:db/id (:block/left e))}
:block/page {:db/id (:db/id (:block/page e))}}) blocks)
blocks (model/sort-page-random-blocks blocks)
id->parent (zipmap (map :db/id blocks)
(map (comp :db/id :block/parent) blocks))
top-level-ids (set (remove #(id->parent (id->parent %)) (map :db/id blocks)))
;; Separate blocks into parent and children groups [parent-children, parent-children]
blocks' (loop [blocks blocks
result []]
(if-let [block (first blocks)]
(if (top-level-ids (:db/id block))
(let [block' (assoc block :block/level 1)]
(recur (rest blocks) (conj result [block'])))
(recur (rest blocks) (conj (vec (butlast result))
(conj (last result) block))))
result))]
(map (fn [[parent & children]]
(if (seq children)
(assoc parent :block/children
(tree children (:db/id parent)))
parent)) blocks')))
parent->children (group-by :block/parent blocks)
id->blocks (zipmap (map :db/id blocks) blocks)
top-level-blocks (filter #(nil?
(id->blocks
(:db/id (:block/parent (id->blocks (:db/id %)))))) blocks)
top-level-blocks' (model/try-sort-by-left top-level-blocks (:block/parent (first top-level-blocks)))]
(map #(tree parent->children %) top-level-blocks')))
(defn- sort-blocks-aux
[parents parent-groups]

View File

@@ -708,13 +708,25 @@
[]
(:selection/blocks @state))
(defn get-selection-block-ids
[]
(->> (sub :selection/blocks)
(defn- get-selected-block-ids
[blocks]
(->> blocks
(keep #(when-let [id (dom/attr % "blockid")]
(uuid id)))
(distinct)))
(defn get-selection-block-ids
[]
(get-selected-block-ids (get-selection-blocks)))
(defn sub-block-selected?
[block-uuid]
(rum/react
(rum/derived-atom [state] [::select-block block-uuid]
(fn [state]
(contains? (set (get-selected-block-ids (:selection/blocks state)))
block-uuid)))))
(defn get-selection-start-block-or-first
[]
(or (get-selection-start-block)
@@ -732,7 +744,6 @@
(defn conj-selection-block!
[block direction]
(dom/add-class! block "selected noselect")
(swap! state assoc
:selection/mode true
:selection/blocks (-> (conj (vec (:selection/blocks @state)) block)
@@ -741,10 +752,18 @@
(defn drop-last-selection-block!
[]
(let [last-block (peek (vec (:selection/blocks @state)))]
(let [direction (:selection/direction @state)
up? (= direction :up)
blocks (:selection/blocks @state)
last-block (if up?
(first blocks)
(peek (vec blocks)))
blocks' (if up?
(rest blocks)
(pop (vec blocks)))]
(swap! state assoc
:selection/mode true
:selection/blocks (pop (vec (:selection/blocks @state))))
:selection/blocks blocks')
last-block))
(defn get-selection-direction
@@ -1344,12 +1363,13 @@
(>= (- now last-time) 3000)))))
(defn input-idle?
[repo]
[repo & {:keys [diff]
:or {diff 1000}}]
(when repo
(or
(when-let [last-time (get-in @state [:editor/last-input-time repo])]
(let [now (util/time-ms)]
(>= (- now last-time) 500)))
(>= (- now last-time) diff)))
;; not in editing mode
(not (get-edit-input-id)))))
@@ -1652,7 +1672,8 @@
(defn edit-in-query-or-refs-component
[]
(let [config (last (get-editor-args))]
(or (:custom-query? config) (:ref? config))))
{:custom-query? (:custom-query? config)
:ref? (:ref? config)}))
(defn set-auth-id-token
[id-token]

View File

@@ -1075,6 +1075,8 @@
(= (get-relative-path "a/b/c/d/g.org" "a/b/c/e/f.org")
"../e/f.org"))
(defn keyname [key] (str (namespace key) "/" (name key)))
#?(:cljs
(defn select-highlight!
[blocks]
@@ -1087,8 +1089,6 @@
(doseq [block blocks]
(d/remove-class! block "selected" "noselect"))))
(defn keyname [key] (str (namespace key) "/" (name key)))
(defn batch [in max-time handler buf-atom]
(async/go-loop [buf buf-atom t (async/timeout max-time)]
(let [[v p] (async/alts! [in t])]