core.cljs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. (ns frontend.modules.outliner.core
  2. (:require [clojure.set :as set]
  3. [clojure.zip :as zip]
  4. [frontend.db :as db]
  5. [frontend.db-schema :as db-schema]
  6. [frontend.db.conn :as conn]
  7. [frontend.db.outliner :as db-outliner]
  8. [frontend.modules.outliner.datascript :as ds]
  9. [frontend.modules.outliner.state :as outliner-state]
  10. [frontend.modules.outliner.tree :as tree]
  11. [frontend.modules.outliner.utils :as outliner-u]
  12. [frontend.state :as state]
  13. [frontend.util :as util]))
  14. (defrecord Block [data])
  15. (defn block
  16. [m]
  17. (assert (map? m) (util/format "block data must be map, got: %s %s" (type m) m))
  18. (->Block m))
  19. (defn get-data
  20. [block]
  21. (:data block))
  22. (defn get-block-by-id
  23. [id]
  24. (let [c (conn/get-conn false)
  25. r (db-outliner/get-by-id c (outliner-u/->block-lookup-ref id))]
  26. (when r (->Block r))))
  27. (defn- get-by-parent-&-left
  28. [parent-id left-id]
  29. (some->
  30. (db-outliner/get-by-parent-&-left
  31. (conn/get-conn false)
  32. [:block/uuid parent-id]
  33. [:block/uuid left-id])
  34. (block)))
  35. (defn- index-blocks-by-left-id
  36. [blocks]
  37. (reduce
  38. (fn [acc block]
  39. (assert (tree/satisfied-inode? block) "Block should match satisfied-inode?.")
  40. (let [left-id (tree/-get-left-id block)]
  41. (when (get acc left-id)
  42. (prn "acc: " acc)
  43. (prn "block: " (:data block))
  44. (throw (js/Error. "There are two blocks have the same left-id")))
  45. (assoc acc left-id block)))
  46. {}
  47. blocks))
  48. (defn get-children
  49. [id]
  50. (let [repo (state/get-current-repo)]
  51. (some->>
  52. (outliner-state/get-by-parent-id repo [:block/uuid id])
  53. (mapv block))))
  54. (defn- update-block-unordered
  55. [block]
  56. (let [parent (:block/parent block)
  57. page (:block/page block)
  58. type (:block/type block)]
  59. (if (and parent page type (= parent page) (= type :heading))
  60. (assoc block :block/unordered false)
  61. (assoc block :block/unordered true))))
  62. (defn- block-with-timestamps
  63. [block]
  64. (let [updated-at (util/time-ms)
  65. block (cond->
  66. (assoc block :block/updated-at updated-at)
  67. (nil? (:block/created-at block))
  68. (assoc :block/created-at updated-at))
  69. ;; content (property/insert-properties (:block/format block)
  70. ;; (or (:block/content block) "")
  71. ;; {:created-at (:block/created-at block)
  72. ;; :updated-at (:block/updated-at block)})
  73. ]
  74. block))
  75. ;; -get-id, -get-parent-id, -get-left-id return block-id
  76. ;; the :block/parent, :block/left should be datascript lookup ref
  77. (extend-type Block
  78. tree/INode
  79. (-get-id [this]
  80. (or
  81. (when-let [block-id (get-in this [:data :block/uuid])]
  82. block-id)
  83. (when-let [db-id (get-in this [:data :db/id])]
  84. (let [uuid (:block/uuid (db/pull db-id))]
  85. (if uuid
  86. uuid
  87. (let [new-id (db/new-block-id)]
  88. (db/transact! [{:db/id db-id
  89. :block/uuid new-id}])
  90. new-id))))))
  91. (-get-parent-id [this]
  92. (-> (get-in this [:data :block/parent])
  93. (outliner-u/->block-id)))
  94. (-set-parent-id [this parent-id]
  95. (outliner-u/check-block-id parent-id)
  96. (update this :data assoc :block/parent [:block/uuid parent-id]))
  97. (-get-left-id [this]
  98. (-> (get-in this [:data :block/left])
  99. (outliner-u/->block-id)))
  100. (-set-left-id [this left-id]
  101. (outliner-u/check-block-id left-id)
  102. (update this :data assoc :block/left [:block/uuid left-id]))
  103. (-get-parent [this]
  104. (when-let [parent-id (tree/-get-parent-id this)]
  105. (get-block-by-id parent-id)))
  106. (-get-left [this]
  107. (let [left-id (tree/-get-left-id this)]
  108. (get-block-by-id left-id)))
  109. (-get-right [this]
  110. (let [left-id (tree/-get-id this)
  111. parent-id (tree/-get-parent-id this)]
  112. (get-by-parent-&-left parent-id left-id)))
  113. (-get-down [this]
  114. (let [parent-id (tree/-get-id this)]
  115. (get-by-parent-&-left parent-id parent-id)))
  116. (-save [this txs-state]
  117. (assert (ds/outliner-txs-state? txs-state)
  118. "db should be satisfied outliner-tx-state?")
  119. (let [this (block (update-block-unordered (:data this)))
  120. m (-> (:data this)
  121. (dissoc :block/children :block/meta :block/top? :block/bottom?)
  122. (util/remove-nils))
  123. m (if (state/enable-block-timestamps?) (block-with-timestamps m) m)
  124. other-tx (:db/other-tx m)
  125. id (:db/id (:data this))]
  126. (when (seq other-tx)
  127. (swap! txs-state (fn [txs]
  128. (vec (concat txs other-tx)))))
  129. (when id
  130. (swap! txs-state (fn [txs]
  131. (vec
  132. (concat txs
  133. (map (fn [attribute]
  134. [:db/retract id attribute])
  135. db-schema/retract-attributes)))))
  136. (when-let [e (:block/page (db/entity id))]
  137. (let [m {:db/id (:db/id e)
  138. :block/updated-at (util/time-ms)}
  139. m (if (:block/created-at e)
  140. m
  141. (assoc m :block/created-at (util/time-ms)))]
  142. (swap! txs-state conj m))))
  143. (swap! txs-state conj (dissoc m :db/other-tx))
  144. this))
  145. (-del [this txs-state children?]
  146. (assert (ds/outliner-txs-state? txs-state)
  147. "db should be satisfied outliner-tx-state?")
  148. (let [block-id (tree/-get-id this)
  149. ids (set (if children?
  150. (let [children (db/get-block-children (state/get-current-repo) block-id)
  151. children-ids (map :block/uuid children)]
  152. (conj children-ids block-id))
  153. [block-id]))
  154. txs (map (fn [id] [:db.fn/retractEntity [:block/uuid id]]) ids)
  155. txs (if-not children?
  156. (let [immediate-children (db/get-block-immediate-children (state/get-current-repo) block-id)]
  157. (if (seq immediate-children)
  158. (let [left-id (tree/-get-id (tree/-get-left this))]
  159. (concat txs
  160. (map-indexed (fn [idx child]
  161. (let [parent [:block/uuid left-id]]
  162. (cond->
  163. {:db/id (:db/id child)
  164. :block/parent parent}
  165. (zero? idx)
  166. (assoc :block/left parent))))
  167. immediate-children)))
  168. txs))
  169. txs)]
  170. (swap! txs-state concat txs)
  171. block-id))
  172. (-get-children [this]
  173. (let [children (get-children (tree/-get-id this))]
  174. (when (seq children)
  175. (let [left-id->block (index-blocks-by-left-id children)]
  176. (loop [sorted-children []
  177. current-node this]
  178. (let [id (tree/-get-id current-node)]
  179. (if-let [right (get left-id->block id)]
  180. (recur (conj sorted-children right) right)
  181. (do
  182. (let [should-equal
  183. (=
  184. (count children)
  185. (count sorted-children))]
  186. (when-not should-equal
  187. (prn "children: " (mapv #(get-in % [:data :block/uuid]) children))
  188. (prn "sorted-children: " (mapv #(get-in % [:data :block/uuid]) sorted-children))
  189. (throw (js/Error. "Number of children and sorted-children are not equal."))))
  190. sorted-children)))))))))
  191. (defn save-node
  192. ([node]
  193. (save-node node nil))
  194. ([node {:keys [txs-state]}]
  195. (if txs-state
  196. (tree/-save node txs-state)
  197. (ds/auto-transact!
  198. [db (ds/new-outliner-txs-state)] {:outliner-op :save-node}
  199. (tree/-save node db)))))
  200. (defn insert-node-as-first-child
  201. "Insert a node as first child."
  202. [txs-state new-node parent-node]
  203. {:pre [(every? tree/satisfied-inode? [new-node parent-node])]}
  204. (let [parent-id (tree/-get-id parent-node)
  205. node (-> (tree/-set-left-id new-node parent-id)
  206. (tree/-set-parent-id parent-id))
  207. right-node (tree/-get-down parent-node)]
  208. (if (tree/satisfied-inode? right-node)
  209. (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
  210. saved-new-node (tree/-save node txs-state)]
  211. (tree/-save new-right-node txs-state)
  212. [saved-new-node new-right-node])
  213. (do
  214. (tree/-save node txs-state)
  215. [node]))))
  216. (defn insert-node-as-sibling
  217. "Insert a node as sibling."
  218. [txs-state new-node left-node]
  219. {:pre [(every? tree/satisfied-inode? [new-node left-node])]}
  220. (when-let [left-id (tree/-get-id left-node)]
  221. (let [node (-> (tree/-set-left-id new-node left-id)
  222. (tree/-set-parent-id (tree/-get-parent-id left-node)))
  223. right-node (tree/-get-right left-node)]
  224. (if (tree/satisfied-inode? right-node)
  225. (let [new-right-node (tree/-set-left-id right-node (tree/-get-id new-node))
  226. saved-new-node (tree/-save node txs-state)]
  227. (tree/-save new-right-node txs-state)
  228. [saved-new-node new-right-node])
  229. (do
  230. (tree/-save node txs-state)
  231. [node])))))
  232. (defn- insert-node-aux
  233. ([new-node target-node sibling? txs-state]
  234. (insert-node-aux new-node target-node sibling? txs-state nil))
  235. ([new-node target-node sibling? txs-state blocks-atom]
  236. (let [result (if sibling?
  237. (insert-node-as-sibling txs-state new-node target-node)
  238. (insert-node-as-first-child txs-state new-node target-node))]
  239. (when blocks-atom
  240. (swap! blocks-atom concat result))
  241. (first result))))
  242. ;; TODO: refactor, move to insert-node
  243. (defn insert-node-as-last-child
  244. [txs-state node target-node]
  245. []
  246. {:pre [(every? tree/satisfied-inode? [node target-node])]}
  247. (let [children (tree/-get-children target-node)
  248. [target-node sibling?] (if (seq children)
  249. [(last children) true]
  250. [target-node false])]
  251. (insert-node-aux node target-node sibling? txs-state)))
  252. (defn insert-node
  253. ([new-node target-node sibling?]
  254. (insert-node new-node target-node sibling? nil))
  255. ([new-node target-node sibling? {:keys [blocks-atom skip-transact? txs-state]
  256. :or {skip-transact? false}}]
  257. (if txs-state
  258. (insert-node-aux new-node target-node sibling? txs-state blocks-atom)
  259. (ds/auto-transact!
  260. [txs-state (ds/new-outliner-txs-state)]
  261. {:outliner-op :insert-node
  262. :skip-transact? skip-transact?}
  263. (insert-node-aux new-node target-node sibling? txs-state blocks-atom)))))
  264. (defn- walk-&-insert-nodes
  265. [loc target-node sibling? transact]
  266. (let [update-node-fn
  267. (fn [node new-node] new-node)]
  268. (if (zip/end? loc)
  269. loc
  270. (if (vector? (zip/node loc))
  271. (recur (zip/next loc) target-node sibling? transact)
  272. (let [left1 (zip/left loc)
  273. left2 (zip/left (zip/left loc))]
  274. (if-let [left (or (and left1 (not (vector? (zip/node left1))) left1)
  275. (and left2 (not (vector? (zip/node left2))) left2))]
  276. ;; found left sibling loc
  277. (let [new-node
  278. (insert-node-aux (zip/node loc) (zip/node left) true transact)]
  279. (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact))
  280. ;; else: need to find parent loc
  281. (if-let [parent (-> loc zip/up zip/left)]
  282. (let [new-node
  283. (insert-node-aux (zip/node loc) (zip/node parent) false transact)]
  284. (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact))
  285. ;; else: not found parent, it should be the root node
  286. (let [new-node
  287. (insert-node-aux (zip/node loc) target-node sibling? transact)]
  288. (recur (zip/next (zip/edit loc update-node-fn new-node)) target-node sibling? transact)))))))))
  289. (defn- get-node-tree-topmost-last-loc
  290. [loc]
  291. (let [result-loc-or-vec (zip/rightmost (zip/down loc))]
  292. (if (vector? (zip/node result-loc-or-vec))
  293. (zip/left result-loc-or-vec)
  294. result-loc-or-vec)))
  295. (defn- get-node-tree-sub-topmost-last-loc
  296. [loc]
  297. (let [topmost-last-loc (get-node-tree-topmost-last-loc loc)
  298. result-vec-or-nil (zip/right topmost-last-loc)]
  299. (when (and (some? result-vec-or-nil)
  300. (vector? (zip/node result-vec-or-nil)))
  301. (get-node-tree-topmost-last-loc result-vec-or-nil))))
  302. (defn insert-nodes
  303. "Insert nodes as children(or siblings) of target-node.
  304. new-nodes-tree is an vector of blocks, e.g [1 [2 3] 4 [5 [6 7]]]"
  305. [new-nodes-tree target-node sibling?]
  306. (ds/auto-transact!
  307. [txs-state (ds/new-outliner-txs-state)] {:outliner-op :insert-nodes}
  308. (let [loc (zip/vector-zip new-nodes-tree)]
  309. ;; TODO: validate new-nodes-tree structure
  310. (let [updated-nodes (walk-&-insert-nodes loc target-node sibling? txs-state)
  311. loc (zip/vector-zip (zip/root updated-nodes))
  312. ;; topmost-last-loc=4, new-nodes-tree=[1 [2 3] 4 [5 [6 7]]]
  313. topmost-last-loc (get-node-tree-topmost-last-loc loc)
  314. ;; sub-topmost-last-loc=5, new-nodes-tree=[1 [2 3] 4 [5 [6 7]]]
  315. sub-topmost-last-loc (get-node-tree-sub-topmost-last-loc loc)
  316. right-node (tree/-get-right target-node)
  317. down-node (tree/-get-down target-node)]
  318. ;; update node's left&parent after inserted nodes
  319. (cond
  320. (and (not sibling?) (some? right-node) (nil? down-node))
  321. nil ;ignore
  322. (and sibling? (some? right-node) topmost-last-loc) ;; right-node.left=N
  323. (let [topmost-last-node (zip/node topmost-last-loc)
  324. updated-node (tree/-set-left-id right-node (tree/-get-id topmost-last-node))]
  325. (tree/-save updated-node txs-state))
  326. (and (not sibling?) (some? down-node) topmost-last-loc) ;; down-node.left=N
  327. (let [topmost-last-node (zip/node topmost-last-loc)
  328. updated-node (tree/-set-left-id down-node (tree/-get-id topmost-last-node))]
  329. (tree/-save updated-node txs-state))
  330. (and sibling? (some? down-node)) ;; unchanged
  331. nil)))))
  332. (defn move-nodes
  333. "Move nodes up/down."
  334. [nodes up?]
  335. (ds/auto-transact!
  336. [txs-state (ds/new-outliner-txs-state)] {:outliner-op :move-nodes}
  337. (let [first-node (first nodes)
  338. last-node (last nodes)
  339. left (tree/-get-left first-node)
  340. move-to-another-parent? (if up?
  341. (= left (tree/-get-parent first-node))
  342. (and (tree/-get-parent last-node)
  343. (nil? (tree/-get-right last-node))))
  344. [up-node down-node] (if up?
  345. [left last-node]
  346. (let [down-node (if move-to-another-parent?
  347. (tree/-get-right (tree/-get-parent last-node))
  348. (tree/-get-right last-node))]
  349. [first-node down-node]))]
  350. (when (and up-node down-node)
  351. (cond
  352. (and move-to-another-parent? up?)
  353. (when-let [target (tree/-get-left up-node)]
  354. (when (and (not (:block/name (:data target))) ; page root block
  355. (not (= target
  356. (when-let [parent (tree/-get-parent first-node)]
  357. (tree/-get-parent parent)))))
  358. (insert-node-as-last-child txs-state first-node target)
  359. (let [parent-id (tree/-get-id target)]
  360. (doseq [node (rest nodes)]
  361. (let [node (tree/-set-parent-id node parent-id)]
  362. (tree/-save node txs-state))))
  363. (when-let [down-node-right (tree/-get-right down-node)]
  364. (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id (tree/-get-parent first-node)))]
  365. (tree/-save down-node-right txs-state)))))
  366. move-to-another-parent? ; down?
  367. (do
  368. (insert-node-as-first-child txs-state first-node down-node)
  369. (let [parent-id (tree/-get-id down-node)]
  370. (doseq [node (rest nodes)]
  371. (let [node (tree/-set-parent-id node parent-id)]
  372. (tree/-save node txs-state))))
  373. (when-let [down-node-down (tree/-get-down down-node)]
  374. (let [down-node-down (tree/-set-left-id down-node-down (tree/-get-id last-node))]
  375. (tree/-save down-node-down txs-state))))
  376. up? ; sibling
  377. (let [first-node (tree/-set-left-id first-node (tree/-get-left-id left))
  378. left (tree/-set-left-id left (tree/-get-id last-node))]
  379. (tree/-save first-node txs-state)
  380. (tree/-save left txs-state)
  381. (when-let [down-node-right (tree/-get-right down-node)]
  382. (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id left))]
  383. (tree/-save down-node-right txs-state))))
  384. :else ; down && sibling
  385. (let [first-node (tree/-set-left-id first-node (tree/-get-id down-node))
  386. down-node (tree/-set-left-id down-node (tree/-get-id left))]
  387. (tree/-save first-node txs-state)
  388. (tree/-save down-node txs-state)
  389. (when-let [down-node-right (tree/-get-right down-node)]
  390. (let [down-node-right (tree/-set-left-id down-node-right (tree/-get-id last-node))]
  391. (tree/-save down-node-right txs-state)))))))))
  392. (defn delete-node
  393. "Delete node from the tree."
  394. [node children?]
  395. {:pre [(tree/satisfied-inode? node)]}
  396. (ds/auto-transact!
  397. [txs-state (ds/new-outliner-txs-state)] {:outliner-op :delete-node}
  398. (let [right-node (tree/-get-right node)]
  399. (tree/-del node txs-state children?)
  400. (when (tree/satisfied-inode? right-node)
  401. (let [left-node (tree/-get-left node)
  402. new-right-node (tree/-set-left-id right-node (tree/-get-id left-node))]
  403. (tree/-save new-right-node txs-state))))))
  404. (defn- get-left-nodes
  405. [node limit]
  406. (let [parent (tree/-get-parent node)]
  407. (loop [node node
  408. limit limit
  409. result []]
  410. (if (zero? limit)
  411. result
  412. (if-let [left (tree/-get-left node)]
  413. (if-not (= left parent)
  414. (recur left (dec limit) (conj result (tree/-get-id left)))
  415. result)
  416. result)))))
  417. (defn delete-nodes
  418. "Delete nodes from the tree.
  419. Args:
  420. start-node: the node at the top of the outliner document.
  421. end-node: the node at the bottom of the outliner document
  422. block-ids: block ids between the start node and end node, including all the
  423. children.
  424. "
  425. [start-node end-node block-ids]
  426. {:pre [(tree/satisfied-inode? start-node)
  427. (tree/satisfied-inode? end-node)]}
  428. (ds/auto-transact!
  429. [txs-state (ds/new-outliner-txs-state)]
  430. {:outliner-op :delete-nodes}
  431. (let [end-node-parents (->>
  432. (db/get-block-parents
  433. (state/get-current-repo)
  434. (tree/-get-id end-node)
  435. 1000)
  436. (map :block/uuid)
  437. (set))
  438. self-block? (contains? end-node-parents (tree/-get-id start-node))]
  439. (if (or (= start-node end-node)
  440. self-block?)
  441. (delete-node start-node true)
  442. (let [sibling? (= (tree/-get-parent-id start-node)
  443. (tree/-get-parent-id end-node))
  444. right-node (tree/-get-right end-node)]
  445. (when (tree/satisfied-inode? right-node)
  446. (let [left-node-id (if sibling?
  447. (tree/-get-id (tree/-get-left start-node))
  448. (let [end-node-left-nodes (get-left-nodes end-node (count block-ids))
  449. parents (->>
  450. (db/get-block-parents
  451. (state/get-current-repo)
  452. (tree/-get-id start-node)
  453. 1000)
  454. (map :block/uuid)
  455. (set))
  456. result (first (set/intersection (set end-node-left-nodes) parents))]
  457. (when-not result
  458. (util/pprint {:parents parents
  459. :end-node-left-nodes end-node-left-nodes}))
  460. result))]
  461. (assert left-node-id "Can't find the left-node-id")
  462. (let [new-right-node (tree/-set-left-id right-node left-node-id)]
  463. (tree/-save new-right-node txs-state))))
  464. (let [txs (db-outliner/del-blocks block-ids)]
  465. (ds/add-txs txs-state txs)))))))
  466. (defn first-child?
  467. [node]
  468. (=
  469. (tree/-get-left-id node)
  470. (tree/-get-parent-id node)))
  471. (defn- first-level?
  472. "Can't be outdented."
  473. [node]
  474. (nil? (tree/-get-parent (tree/-get-parent node))))
  475. (defn get-right-siblings
  476. [node]
  477. {:pre [(tree/satisfied-inode? node)]}
  478. (when-let [parent (tree/-get-parent node)]
  479. (let [children (tree/-get-children parent)]
  480. (->> (split-with #(not= (tree/-get-id node) (tree/-get-id %)) children)
  481. last
  482. rest))))
  483. (defn- logical-outdenting
  484. [txs-state parent nodes first-node last-node last-node-right parent-parent-id parent-right]
  485. (some-> last-node-right
  486. (tree/-set-left-id (tree/-get-left-id first-node))
  487. (tree/-save txs-state))
  488. (let [first-node (tree/-set-left-id first-node (tree/-get-id parent))]
  489. (doseq [node (cons first-node (rest nodes))]
  490. (-> (tree/-set-parent-id node parent-parent-id)
  491. (tree/-save txs-state))))
  492. (some-> parent-right
  493. (tree/-set-left-id (tree/-get-id last-node))
  494. (tree/-save txs-state)))
  495. (defn indent-outdent-nodes
  496. [nodes indent?]
  497. (ds/auto-transact!
  498. [txs-state (ds/new-outliner-txs-state)] {:outliner-op :indent-outdent-nodes}
  499. (let [first-node (first nodes)
  500. last-node (last nodes)]
  501. (if indent?
  502. (when-not (first-child? first-node)
  503. (let [first-node-left-id (tree/-get-left-id first-node)
  504. last-node-right (tree/-get-right last-node)
  505. parent-or-last-child-id (or (-> (db/get-block-immediate-children (state/get-current-repo)
  506. first-node-left-id)
  507. last
  508. :block/uuid)
  509. first-node-left-id)
  510. first-node (tree/-set-left-id first-node parent-or-last-child-id)]
  511. (doseq [node (cons first-node (rest nodes))]
  512. (-> (tree/-set-parent-id node first-node-left-id)
  513. (tree/-save txs-state)))
  514. (some-> last-node-right
  515. (tree/-set-left-id first-node-left-id)
  516. (tree/-save txs-state))))
  517. (when-not (first-level? first-node)
  518. (let [parent (tree/-get-parent first-node)
  519. parent-parent-id (tree/-get-parent-id parent)
  520. parent-right (tree/-get-right parent)
  521. last-node-right (tree/-get-right last-node)
  522. last-node-id (tree/-get-id last-node)]
  523. (logical-outdenting txs-state parent nodes first-node last-node last-node-right parent-parent-id parent-right)
  524. (when-not (state/logical-outdenting?)
  525. ;; direct outdenting (the old behavior)
  526. (let [right-siblings (get-right-siblings last-node)
  527. right-siblings (doall
  528. (map (fn [sibling]
  529. (some->
  530. (tree/-set-parent-id sibling last-node-id)
  531. (tree/-save txs-state)))
  532. right-siblings))]
  533. (when-let [last-node-right (first right-siblings)]
  534. (let [last-node-children (tree/-get-children last-node)
  535. left-id (if (seq last-node-children)
  536. (tree/-get-id (last last-node-children))
  537. last-node-id)]
  538. (when left-id
  539. (some-> (tree/-set-left-id last-node-right left-id)
  540. (tree/-save txs-state)))))))))))))
  541. (defn- set-nodes-page-aux
  542. [node page page-format txs-state]
  543. (let [new-node (update node :data assoc
  544. :block/page page
  545. :block/format page-format)]
  546. (tree/-save new-node txs-state)
  547. (doseq [n (tree/-get-children new-node)]
  548. (set-nodes-page-aux n page page-format txs-state))))
  549. (defn- set-nodes-page
  550. [node target-node txs-state]
  551. (let [page (or (get-in target-node [:data :block/page])
  552. {:db/id (get-in target-node [:data :db/id])}) ; or page block
  553. page-format (:block/format (db/entity (or (:db/id page) page)))]
  554. (set-nodes-page-aux node page page-format txs-state)))
  555. (defn move-subtree
  556. "Move subtree to a destination position in the relation tree.
  557. Args:
  558. root: root of subtree
  559. target-node: the destination
  560. sibling?: as sibling of the target-node or child"
  561. [root target-node sibling?]
  562. {:pre [(every? tree/satisfied-inode? [root target-node])
  563. (boolean? sibling?)]}
  564. (let [target-node-id (tree/-get-id target-node)]
  565. (when-not (or (and sibling?
  566. (= (tree/-get-left-id root) target-node-id)
  567. (not= (tree/-get-parent-id root) target-node-id))
  568. (and (not sibling?)
  569. (= (tree/-get-left-id root) target-node-id)
  570. (= (tree/-get-parent-id root) target-node-id)))
  571. (let [root-page (:db/id (:block/page (:data root)))
  572. target-page (:db/id (:block/page (:data target-node)))
  573. not-same-page? (not= root-page target-page)
  574. opts (cond-> {:outliner-op :move-subtree}
  575. not-same-page?
  576. (assoc :from-page root-page
  577. :target-page target-page))]
  578. (ds/auto-transact!
  579. [txs-state (ds/new-outliner-txs-state)] opts
  580. (let [left-node-id (tree/-get-left-id root)
  581. right-node (tree/-get-right root)]
  582. (when (tree/satisfied-inode? right-node)
  583. (let [new-right-node (tree/-set-left-id right-node left-node-id)]
  584. (tree/-save new-right-node txs-state)))
  585. (let [new-root (first (if sibling?
  586. (insert-node-as-sibling txs-state root target-node)
  587. (insert-node-as-first-child txs-state root target-node)))]
  588. (set-nodes-page new-root target-node txs-state))))))))
  589. (defn get-right-node
  590. [node]
  591. {:pre [(tree/satisfied-inode? node)]}
  592. (tree/-get-right node))