| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- (ns frontend.modules.outliner.core
- (:require [clojure.set :as set]
- [clojure.zip :as zip]
- [frontend.db :as db]
- [frontend.db-schema :as db-schema]
- [frontend.db.conn :as conn]
- [frontend.db.outliner :as db-outliner]
- [frontend.modules.outliner.datascript :as ds]
- [frontend.modules.outliner.state :as outliner-state]
- [frontend.modules.outliner.tree :as tree]
- [frontend.modules.outliner.utils :as outliner-u]
- [frontend.state :as state]
- [frontend.util :as util]))
- (defrecord Block [data])
- (defn block
- [m]
- (assert (map? m) (util/format "block data must be map, got: %s %s" (type m) m))
- (->Block m))
- (defn get-data
- [block]
- (:data block))
- (defn get-block-by-id
- [id]
- (let [c (conn/get-conn false)
- r (db-outliner/get-by-id c (outliner-u/->block-lookup-ref id))]
- (when r (->Block r))))
- (defn- get-by-parent-&-left
- [parent-id left-id]
- (some->
- (db-outliner/get-by-parent-&-left
- (conn/get-conn false)
- [:block/uuid parent-id]
- [:block/uuid left-id])
- (block)))
- (defn- index-blocks-by-left-id
- [blocks]
- (reduce
- (fn [acc block]
- (assert (tree/satisfied-inode? block) "Block should match satisfied-inode?.")
- (let [left-id (tree/-get-left-id block)]
- (when (get acc left-id)
- (prn "acc: " acc)
- (prn "block: " (:data block))
- (throw (js/Error. "There are two blocks have the same left-id")))
- (assoc acc left-id block)))
- {}
- blocks))
- (defn get-children
- [id]
- (let [repo (state/get-current-repo)]
- (some->>
- (outliner-state/get-by-parent-id repo [:block/uuid id])
- (mapv block))))
- (defn- update-block-unordered
- [block]
- (let [parent (:block/parent block)
- page (:block/page block)
- type (:block/type block)]
- (if (and parent page type (= parent page) (= type :heading))
- (assoc block :block/unordered false)
- (assoc block :block/unordered true))))
- (defn- block-with-timestamps
- [block]
- (let [updated-at (util/time-ms)
- block (cond->
- (assoc block :block/updated-at updated-at)
- (nil? (:block/created-at block))
- (assoc :block/created-at updated-at))
- ;; content (property/insert-properties (:block/format block)
- ;; (or (:block/content block) "")
- ;; {:created-at (:block/created-at block)
- ;; :updated-at (:block/updated-at block)})
- ]
- block))
- ;; -get-id, -get-parent-id, -get-left-id return block-id
- ;; the :block/parent, :block/left should be datascript lookup ref
- (extend-type Block
- tree/INode
- (-get-id [this]
- (or
- (when-let [block-id (get-in this [:data :block/uuid])]
- block-id)
- (when-let [db-id (get-in this [:data :db/id])]
- (let [uuid (:block/uuid (db/pull db-id))]
- (if uuid
- uuid
- (let [new-id (db/new-block-id)]
- (db/transact! [{:db/id db-id
- :block/uuid new-id}])
- new-id))))))
- (-get-parent-id [this]
- (-> (get-in this [:data :block/parent])
- (outliner-u/->block-id)))
- (-set-parent-id [this parent-id]
- (outliner-u/check-block-id parent-id)
- (update this :data assoc :block/parent [:block/uuid parent-id]))
- (-get-left-id [this]
- (-> (get-in this [:data :block/left])
- (outliner-u/->block-id)))
- (-set-left-id [this left-id]
- (outliner-u/check-block-id left-id)
- (update this :data assoc :block/left [:block/uuid left-id]))
- (-get-parent [this]
- (when-let [parent-id (tree/-get-parent-id this)]
- (get-block-by-id parent-id)))
- (-get-left [this]
- (let [left-id (tree/-get-left-id this)]
- (get-block-by-id left-id)))
- (-get-right [this]
- (let [left-id (tree/-get-id this)
- parent-id (tree/-get-parent-id this)]
- (get-by-parent-&-left parent-id left-id)))
- (-get-down [this]
- (let [parent-id (tree/-get-id this)]
- (get-by-parent-&-left parent-id parent-id)))
- (-save [this txs-state]
- (assert (ds/outliner-txs-state? txs-state)
- "db should be satisfied outliner-tx-state?")
- (let [this (block (update-block-unordered (:data this)))
- m (-> (:data this)
- (dissoc :block/children :block/meta :block/top? :block/bottom?)
- (util/remove-nils))
- m (if (state/enable-block-timestamps?) (block-with-timestamps m) m)
- other-tx (:db/other-tx m)
- id (:db/id (:data this))]
- (when (seq other-tx)
- (swap! txs-state (fn [txs]
- (vec (concat txs other-tx)))))
- (when id
- (swap! txs-state (fn [txs]
- (vec
- (concat txs
- (map (fn [attribute]
- [:db/retract id attribute])
- db-schema/retract-attributes)))))
- (when-let [e (:block/page (db/entity id))]
- (let [m {:db/id (:db/id e)
- :block/updated-at (util/time-ms)}
- m (if (:block/created-at e)
- m
- (assoc m :block/created-at (util/time-ms)))]
- (swap! txs-state conj m))))
- (swap! txs-state conj (dissoc m :db/other-tx))
- this))
- (-del [this txs-state children?]
- (assert (ds/outliner-txs-state? txs-state)
- "db should be satisfied outliner-tx-state?")
- (let [block-id (tree/-get-id this)
- ids (set (if children?
- (let [children (db/get-block-children (state/get-current-repo) block-id)
- children-ids (map :block/uuid children)]
- (conj children-ids block-id))
- [block-id]))
- txs (map (fn [id] [:db.fn/retractEntity [:block/uuid id]]) ids)
- txs (if-not children?
- (let [immediate-children (db/get-block-immediate-children (state/get-current-repo) block-id)]
- (if (seq immediate-children)
- (let [left-id (tree/-get-id (tree/-get-left this))]
- (concat txs
- (map-indexed (fn [idx child]
- (let [parent [:block/uuid left-id]]
- (cond->
- {:db/id (:db/id child)
- :block/parent parent}
- (zero? idx)
- (assoc :block/left parent))))
- immediate-children)))
- txs))
- txs)]
- (swap! txs-state concat txs)
- block-id))
- (-get-children [this]
- (let [children (get-children (tree/-get-id this))]
- (when (seq children)
- (let [left-id->block (index-blocks-by-left-id children)]
- (loop [sorted-children []
- current-node this]
- (let [id (tree/-get-id current-node)]
- (if-let [right (get left-id->block id)]
- (recur (conj sorted-children right) right)
- (do
- (let [should-equal
- (=
- (count children)
- (count sorted-children))]
- (when-not should-equal
- (prn "children: " (mapv #(get-in % [:data :block/uuid]) children))
- (prn "sorted-children: " (mapv #(get-in % [:data :block/uuid]) sorted-children))
- (throw (js/Error. "Number of children and sorted-children are not equal."))))
- sorted-children)))))))))
- (defn save-node
- ([node]
- (save-node node nil))
- ([node {:keys [txs-state]}]
- (if txs-state
- (tree/-save node txs-state)
- (ds/auto-transact!
- [db (ds/new-outliner-txs-state)] {:outliner-op :save-node}
- (tree/-save node db)))))
- (defn insert-node-as-first-child
- "Insert a node as first child."
- [txs-state new-node parent-node]
- {:pre [(every? tree/satisfied-inode? [new-node parent-node])]}
- (let [parent-id (tree/-get-id parent-node)
- node (-> (tree/-set-left-id new-node parent-id)
- (tree/-set-parent-id parent-id))
- right-node (tree/-get-down parent-node)]
- (if (tree/satisfied-inode? right-node)
- (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
- saved-new-node (tree/-save node txs-state)]
- (tree/-save new-right-node txs-state)
- [saved-new-node new-right-node])
- (do
- (tree/-save node txs-state)
- [node]))))
- (defn insert-node-as-sibling
- "Insert a node as sibling."
- [txs-state new-node left-node]
- {:pre [(every? tree/satisfied-inode? [new-node left-node])]}
- (when-let [left-id (tree/-get-id left-node)]
- (let [node (-> (tree/-set-left-id new-node left-id)
- (tree/-set-parent-id (tree/-get-parent-id left-node)))
- right-node (tree/-get-right left-node)]
- (if (tree/satisfied-inode? right-node)
- (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
- saved-new-node (tree/-save node txs-state)]
- (tree/-save new-right-node txs-state)
- [saved-new-node new-right-node])
- (do
- (tree/-save node txs-state)
- [node])))))
- (defn- insert-node-aux
- ([new-node target-node sibling? txs-state]
- (insert-node-aux new-node target-node sibling? txs-state nil))
- ([new-node target-node sibling? txs-state blocks-atom]
- (let [result (if sibling?
- (insert-node-as-sibling txs-state new-node target-node)
- (insert-node-as-first-child txs-state new-node target-node))]
- (when blocks-atom
- (swap! blocks-atom concat result))
- (first result))))
- ;; TODO: refactor, move to insert-node
- (defn insert-node-as-last-child
- [txs-state node target-node]
- []
- {:pre [(every? tree/satisfied-inode? [node target-node])]}
- (let [children (tree/-get-children target-node)
- [target-node sibling?] (if (seq children)
- [(last children) true]
- [target-node false])]
- (insert-node-aux node target-node sibling? txs-state)))
- (defn insert-node
- ([new-node target-node sibling?]
- (insert-node new-node target-node sibling? nil))
- ([new-node target-node sibling? {:keys [blocks-atom skip-transact? txs-state]
- :or {skip-transact? false}}]
- (if txs-state
- (insert-node-aux new-node target-node sibling? txs-state blocks-atom)
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)]
- {:outliner-op :insert-node
- :skip-transact? skip-transact?}
- (insert-node-aux new-node target-node sibling? txs-state blocks-atom)))))
- (defn- walk-&-insert-nodes
- [loc target-node sibling? transact]
- (let [update-node-fn
- (fn [node new-node] new-node)]
- (if (zip/end? loc)
- loc
- (if (vector? (zip/node loc))
- (recur (zip/next loc) target-node sibling? transact)
- (let [left1 (zip/left loc)
- left2 (zip/left (zip/left loc))]
- (if-let [left (or (and left1 (not (vector? (zip/node left1))) left1)
- (and left2 (not (vector? (zip/node left2))) left2))]
- ;; found left sibling loc
- (let [new-node
- (insert-node-aux (zip/node loc) (zip/node left) true transact)]
- (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact))
- ;; else: need to find parent loc
- (if-let [parent (-> loc zip/up zip/left)]
- (let [new-node
- (insert-node-aux (zip/node loc) (zip/node parent) false transact)]
- (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact))
- ;; else: not found parent, it should be the root node
- (let [new-node
- (insert-node-aux (zip/node loc) target-node sibling? transact)]
- (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact)))))))))
- (defn- get-node-tree-topmost-last-loc
- [loc]
- (let [result-loc-or-vec (zip/rightmost (zip/down loc))]
- (if (vector? (zip/node result-loc-or-vec))
- (zip/left result-loc-or-vec)
- result-loc-or-vec)))
- (defn- get-node-tree-sub-topmost-last-loc
- [loc]
- (let [topmost-last-loc (get-node-tree-topmost-last-loc loc)
- result-vec-or-nil (zip/right topmost-last-loc)]
- (when (and (some? result-vec-or-nil)
- (vector? (zip/node result-vec-or-nil)))
- (get-node-tree-topmost-last-loc result-vec-or-nil))))
- (defn insert-nodes
- "Insert nodes as children(or siblings) of target-node.
- new-nodes-tree is an vector of blocks, e.g [1 [2 3] 4 [5 [6 7]]]"
- [new-nodes-tree target-node sibling?]
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)] {:outliner-op :insert-nodes}
- (let [loc (zip/vector-zip new-nodes-tree)]
- ;; TODO: validate new-nodes-tree structure
- (let [updated-nodes (walk-&-insert-nodes loc target-node sibling? txs-state)
- loc (zip/vector-zip (zip/root updated-nodes))
- ;; topmost-last-loc=4, new-nodes-tree=[1 [2 3] 4 [5 [6 7]]]
- topmost-last-loc (get-node-tree-topmost-last-loc loc)
- ;; sub-topmost-last-loc=5, new-nodes-tree=[1 [2 3] 4 [5 [6 7]]]
- sub-topmost-last-loc (get-node-tree-sub-topmost-last-loc loc)
- right-node (tree/-get-right target-node)
- down-node (tree/-get-down target-node)]
- ;; update node's left&parent after inserted nodes
- (cond
- (and (not sibling?) (some? right-node) (nil? down-node))
- nil ;ignore
- (and sibling? (some? right-node) topmost-last-loc) ;; right-node.left=N
- (let [topmost-last-node (zip/node topmost-last-loc)
- updated-node (tree/-set-left-id right-node (tree/-get-id topmost-last-node))]
- (tree/-save updated-node txs-state))
- (and (not sibling?) (some? down-node) topmost-last-loc) ;; down-node.left=N
- (let [topmost-last-node (zip/node topmost-last-loc)
- updated-node (tree/-set-left-id down-node (tree/-get-id topmost-last-node))]
- (tree/-save updated-node txs-state))
- (and sibling? (some? down-node)) ;; unchanged
- nil)))))
- (defn move-nodes
- "Move nodes up/down."
- [nodes up?]
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)] {:outliner-op :move-nodes}
- (let [first-node (first nodes)
- last-node (last nodes)
- left (tree/-get-left first-node)
- move-to-another-parent? (if up?
- (= left (tree/-get-parent first-node))
- (and (tree/-get-parent last-node)
- (nil? (tree/-get-right last-node))))
- [up-node down-node] (if up?
- [left last-node]
- (let [down-node (if move-to-another-parent?
- (tree/-get-right (tree/-get-parent last-node))
- (tree/-get-right last-node))]
- [first-node down-node]))]
- (when (and up-node down-node)
- (cond
- (and move-to-another-parent? up?)
- (when-let [target (tree/-get-left up-node)]
- (when (and (not (:block/name (:data target))) ; page root block
- (not (= target
- (when-let [parent (tree/-get-parent first-node)]
- (tree/-get-parent parent)))))
- (insert-node-as-last-child txs-state first-node target)
- (let [parent-id (tree/-get-id target)]
- (doseq [node (rest nodes)]
- (let [node (tree/-set-parent-id node parent-id)]
- (tree/-save node txs-state))))
- (when-let [down-node-right (tree/-get-right down-node)]
- (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id (tree/-get-parent first-node)))]
- (tree/-save down-node-right txs-state)))))
- move-to-another-parent? ; down?
- (do
- (insert-node-as-first-child txs-state first-node down-node)
- (let [parent-id (tree/-get-id down-node)]
- (doseq [node (rest nodes)]
- (let [node (tree/-set-parent-id node parent-id)]
- (tree/-save node txs-state))))
- (when-let [down-node-down (tree/-get-down down-node)]
- (let [down-node-down (tree/-set-left-id down-node-down (tree/-get-id last-node))]
- (tree/-save down-node-down txs-state))))
- up? ; sibling
- (let [first-node (tree/-set-left-id first-node (tree/-get-left-id left))
- left (tree/-set-left-id left (tree/-get-id last-node))]
- (tree/-save first-node txs-state)
- (tree/-save left txs-state)
- (when-let [down-node-right (tree/-get-right down-node)]
- (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id left))]
- (tree/-save down-node-right txs-state))))
- :else ; down && sibling
- (let [first-node (tree/-set-left-id first-node (tree/-get-id down-node))
- down-node (tree/-set-left-id down-node (tree/-get-id left))]
- (tree/-save first-node txs-state)
- (tree/-save down-node txs-state)
- (when-let [down-node-right (tree/-get-right down-node)]
- (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id last-node))]
- (tree/-save down-node-right txs-state)))))))))
- (defn delete-node
- "Delete node from the tree."
- [node children?]
- {:pre [(tree/satisfied-inode? node)]}
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)] {:outliner-op :delete-node}
- (let [right-node (tree/-get-right node)]
- (tree/-del node txs-state children?)
- (when (tree/satisfied-inode? right-node)
- (let [left-node (tree/-get-left node)
- new-right-node (tree/-set-left-id right-node (tree/-get-id left-node))]
- (tree/-save new-right-node txs-state))))))
- (defn- get-left-nodes
- [node limit]
- (let [parent (tree/-get-parent node)]
- (loop [node node
- limit limit
- result []]
- (if (zero? limit)
- result
- (if-let [left (tree/-get-left node)]
- (if-not (= left parent)
- (recur left (dec limit) (conj result (tree/-get-id left)))
- result)
- result)))))
- (defn delete-nodes
- "Delete nodes from the tree.
- Args:
- start-node: the node at the top of the outliner document.
- end-node: the node at the bottom of the outliner document
- block-ids: block ids between the start node and end node, including all the
- children.
- "
- [start-node end-node block-ids]
- {:pre [(tree/satisfied-inode? start-node)
- (tree/satisfied-inode? end-node)]}
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)]
- {:outliner-op :delete-nodes}
- (let [end-node-parents (->>
- (db/get-block-parents
- (state/get-current-repo)
- (tree/-get-id end-node)
- 1000)
- (map :block/uuid)
- (set))
- self-block? (contains? end-node-parents (tree/-get-id start-node))]
- (if (or (= start-node end-node)
- self-block?)
- (delete-node start-node true)
- (let [sibling? (= (tree/-get-parent-id start-node)
- (tree/-get-parent-id end-node))
- right-node (tree/-get-right end-node)]
- (when (tree/satisfied-inode? right-node)
- (let [left-node-id (if sibling?
- (tree/-get-id (tree/-get-left start-node))
- (let [end-node-left-nodes (get-left-nodes end-node (count block-ids))
- parents (->>
- (db/get-block-parents
- (state/get-current-repo)
- (tree/-get-id start-node)
- 1000)
- (map :block/uuid)
- (set))
- result (first (set/intersection (set end-node-left-nodes) parents))]
- (when-not result
- (util/pprint {:parents parents
- :end-node-left-nodes end-node-left-nodes}))
- result))]
- (assert left-node-id "Can't find the left-node-id")
- (let [new-right-node (tree/-set-left-id right-node left-node-id)]
- (tree/-save new-right-node txs-state))))
- (let [txs (db-outliner/del-blocks block-ids)]
- (ds/add-txs txs-state txs)))))))
- (defn first-child?
- [node]
- (=
- (tree/-get-left-id node)
- (tree/-get-parent-id node)))
- (defn- first-level?
- "Can't be outdented."
- [node]
- (nil? (tree/-get-parent (tree/-get-parent node))))
- (defn get-right-siblings
- [node]
- {:pre [(tree/satisfied-inode? node)]}
- (when-let [parent (tree/-get-parent node)]
- (let [children (tree/-get-children parent)]
- (->> (split-with #(not= (tree/-get-id node) (tree/-get-id %)) children)
- last
- rest))))
- (defn- logical-outdenting
- [txs-state parent nodes first-node last-node last-node-right parent-parent-id parent-right]
- (some-> last-node-right
- (tree/-set-left-id (tree/-get-left-id first-node))
- (tree/-save txs-state))
- (let [first-node (tree/-set-left-id first-node (tree/-get-id parent))]
- (doseq [node (cons first-node (rest nodes))]
- (-> (tree/-set-parent-id node parent-parent-id)
- (tree/-save txs-state))))
- (some-> parent-right
- (tree/-set-left-id (tree/-get-id last-node))
- (tree/-save txs-state)))
- (defn indent-outdent-nodes
- [nodes indent?]
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)] {:outliner-op :indent-outdent-nodes}
- (let [first-node (first nodes)
- last-node (last nodes)]
- (if indent?
- (when-not (first-child? first-node)
- (let [first-node-left-id (tree/-get-left-id first-node)
- last-node-right (tree/-get-right last-node)
- parent-or-last-child-id (or (-> (db/get-block-immediate-children (state/get-current-repo)
- first-node-left-id)
- last
- :block/uuid)
- first-node-left-id)
- first-node (tree/-set-left-id first-node parent-or-last-child-id)]
- (doseq [node (cons first-node (rest nodes))]
- (-> (tree/-set-parent-id node first-node-left-id)
- (tree/-save txs-state)))
- (some-> last-node-right
- (tree/-set-left-id first-node-left-id)
- (tree/-save txs-state))))
- (when-not (first-level? first-node)
- (let [parent (tree/-get-parent first-node)
- parent-parent-id (tree/-get-parent-id parent)
- parent-right (tree/-get-right parent)
- last-node-right (tree/-get-right last-node)
- last-node-id (tree/-get-id last-node)]
- (logical-outdenting txs-state parent nodes first-node last-node last-node-right parent-parent-id parent-right)
- (when-not (state/logical-outdenting?)
- ;; direct outdenting (the old behavior)
- (let [right-siblings (get-right-siblings last-node)
- right-siblings (doall
- (map (fn [sibling]
- (some->
- (tree/-set-parent-id sibling last-node-id)
- (tree/-save txs-state)))
- right-siblings))]
- (when-let [last-node-right (first right-siblings)]
- (let [last-node-children (tree/-get-children last-node)
- left-id (if (seq last-node-children)
- (tree/-get-id (last last-node-children))
- last-node-id)]
- (when left-id
- (some-> (tree/-set-left-id last-node-right left-id)
- (tree/-save txs-state)))))))))))))
- (defn- set-nodes-page-aux
- [node page page-format txs-state]
- (let [new-node (update node :data assoc
- :block/page page
- :block/format page-format)]
- (tree/-save new-node txs-state)
- (doseq [n (tree/-get-children new-node)]
- (set-nodes-page-aux n page page-format txs-state))))
- (defn- set-nodes-page
- [node target-node txs-state]
- (let [page (or (get-in target-node [:data :block/page])
- {:db/id (get-in target-node [:data :db/id])}) ; or page block
- page-format (:block/format (db/entity (or (:db/id page) page)))]
- (set-nodes-page-aux node page page-format txs-state)))
- (defn move-subtree
- "Move subtree to a destination position in the relation tree.
- Args:
- root: root of subtree
- target-node: the destination
- sibling?: as sibling of the target-node or child"
- [root target-node sibling?]
- {:pre [(every? tree/satisfied-inode? [root target-node])
- (boolean? sibling?)]}
- (let [target-node-id (tree/-get-id target-node)]
- (when-not (or (and sibling?
- (= (tree/-get-left-id root) target-node-id)
- (not= (tree/-get-parent-id root) target-node-id))
- (and (not sibling?)
- (= (tree/-get-left-id root) target-node-id)
- (= (tree/-get-parent-id root) target-node-id)))
- (let [root-page (:db/id (:block/page (:data root)))
- target-page (:db/id (:block/page (:data target-node)))
- not-same-page? (not= root-page target-page)
- opts (cond-> {:outliner-op :move-subtree}
- not-same-page?
- (assoc :from-page root-page
- :target-page target-page))]
- (ds/auto-transact!
- [txs-state (ds/new-outliner-txs-state)] opts
- (let [left-node-id (tree/-get-left-id root)
- right-node (tree/-get-right root)]
- (when (tree/satisfied-inode? right-node)
- (let [new-right-node (tree/-set-left-id right-node left-node-id)]
- (tree/-save new-right-node txs-state)))
- (let [new-root (first (if sibling?
- (insert-node-as-sibling txs-state root target-node)
- (insert-node-as-first-child txs-state root target-node)))]
- (set-nodes-page new-root target-node txs-state))))))))
- (defn get-right-node
- [node]
- {:pre [(tree/satisfied-inode? node)]}
- (tree/-get-right node))
|