diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index a07d99436c..e61880ec2a 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -613,7 +613,11 @@ (defn sort-by-left [blocks parent] - (assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node") + ;; (prn {:blocks blocks + ;; :blocks-count (count blocks) + ;; :block-left-count (frequencies (map :block/left blocks)) + ;; :parent parent}) + ;; (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 []] diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index a36ec4218a..572cf44bf2 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -227,6 +227,7 @@ (not= current-id (cljs.core/uuid block-id)) (db/entity [:block/uuid (cljs.core/uuid block-id)]))) +;; TODO: (defn- create-file-if-not-exists! [repo format page value] (let [format (name format) @@ -744,20 +745,23 @@ (recur parent blocks) end-block)) +(defn- get-top-level-end-node + [blocks] + (let [end-block (last blocks) + end-block-parent (get-end-block-parent end-block blocks)] + (outliner-core/block end-block-parent))) + (defn delete-blocks! [repo block-uuids] (when (seq block-uuids) (let [lookup-refs (map (fn [id] [:block/uuid id]) block-uuids) blocks (db/pull-many repo '[*] lookup-refs)] (let [start-node (outliner-core/block (first blocks)) - end-block (last blocks) - end-block-parent (get-end-block-parent end-block blocks) - end-node (outliner-core/block end-block-parent)] + end-node (get-top-level-end-node blocks)] (outliner-core/delete-nodes start-node end-node lookup-refs) (let [opts {:key :block/change :data blocks}] - (db/refresh repo opts)) - (repo-handler/push-if-auto-enabled! repo))))) + (db/refresh repo opts)))))) (defn remove-block-property! [block-id key] @@ -1544,25 +1548,26 @@ (expand/cycle!))) (defn on-tab - "direction = :left|:right, only indent when blocks are siblings" + "direction = :left|:right, only indent or outdent when blocks are siblings" [direction] (fn [e] (when-let [repo (state/get-current-repo)] (let [blocks (seq (state/get-selection-blocks))] (cond (seq blocks) - (let [ids (map (fn [block] (when-let [id (dom/attr block "blockid")] - (medley/uuid id))) blocks)] - - ;; (repo-handler/transact-react-and-alter-file! - ;; repo - ;; (concat - ;; blocks - ;; after-blocks) - ;; {:key :block/change - ;; :data (map (fn [block] (assoc block :block/page page)) blocks)} - ;; [[file-path new-content]]) - ) + (let [lookup-refs (->> (map (fn [block] (when-let [id (dom/attr block "blockid")] + [:block/uuid (medley/uuid id)])) blocks) + (remove nil?)) + blocks (db/pull-many repo '[*] lookup-refs) + end-node (get-top-level-end-node blocks) + end-node-parent (tree/-get-parent end-node) + top-level-nodes (->> (filter #(= (get-in end-node-parent [:data :db/id]) + (get-in % [:block/parent :db/id])) blocks) + (map outliner-core/block))] + (outliner-core/indent-outdent-nodes top-level-nodes (= direction :right)) + (let [opts {:key :block/change + :data blocks}] + (db/refresh repo opts))) (gdom/getElement "date-time-picker") nil @@ -1932,6 +1937,7 @@ :else nil)))) +;; TODO: merge indent-on-tab, outdent-on-shift-tab, on-tab (defn indent-on-tab ([state] (indent-on-tab state 100)) @@ -1944,9 +1950,7 @@ (state/set-editor-op! :indent-outdent) (let [{:keys [block block-parent-id value config]} (get-state state) current-node (outliner-core/block block) - first-child? (= - (tree/-get-left-id current-node) - (tree/-get-parent-id current-node)) ] + first-child? (outliner-core/first-child? current-node)] (when-not first-child? (let [left (tree/-get-left current-node) children-of-left (tree/-get-children left)] diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index 7a106b1ccf..6913315c55 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -1,5 +1,6 @@ (ns frontend.modules.outliner.core (:require [frontend.modules.outliner.tree :as tree] + [frontend.db :as db] [frontend.db.outliner :as db-outliner] [frontend.db.conn :as conn] [frontend.modules.outliner.utils :as outliner-u] @@ -270,23 +271,69 @@ (db-outliner/del-blocks conn block-ids) (outliner-file/sync-to-file start-node)))) +(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 indent-outdent-nodes + [nodes indent?] + (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)] + ;; (prn {:parent-or-last-child-id parent-or-last-child-id + ;; :parent-content (:block/content (db/pull [:block/uuid parent-or-last-child-id])) + ;; :last-node-right last-node-right + ;; :content (:block/content (db/pull (get-in last-node-right [:data :db/id])))}) + (-> (tree/-set-left-id first-node parent-or-last-child-id) + (tree/-save)) + (doseq [node nodes] + (-> (tree/-set-parent-id node first-node-left-id) + (tree/-save))) + (some-> last-node-right + (tree/-set-left-id first-node-left-id) + (tree/-save)) + (outliner-file/sync-to-file first-node))) + (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)] + (doseq [node nodes] + (-> (tree/-set-parent-id node parent-parent-id) + (tree/-save))) + (some-> parent-right + (tree/-set-left-id (tree/-get-id last-node)) + (tree/-save))))))) + (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] + sibling?: as sibling of the target-node or child" + [root target-node sibling?] {:pre [(every? tree/satisfied-inode? [root target-node]) - (boolean? sibling)]} + (boolean? sibling?)]} (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))) - (if sibling - (insert-node-as-sibling root target-node) - (insert-node-as-first-child root target-node)))) + (insert-node root target-node sibling?))) (defn move-subtree "Move subtree to a destination position in the relation tree.