Преглед на файлове

fix: drag drop on non consecutive blocks

close #5267
Tienson Qin преди 3 години
родител
ревизия
eb42972ef9
променени са 3 файла, в които са добавени 122 реда и са изтрити 21 реда
  1. 6 3
      shadow-cljs.edn
  2. 74 0
      src/main/frontend/db/model.cljs
  3. 42 18
      src/main/frontend/modules/outliner/core.cljs

+ 6 - 3
shadow-cljs.edn

@@ -29,7 +29,8 @@
                            :source-map         true
                            :externs            ["datascript/externs.js"
                                                 "externs.js"]
-                           :warnings           {:fn-deprecated false}}
+                           :warnings           {:fn-deprecated false
+                                                :redef false}}
         :closure-defines  {goog.debug.LOGGING_ENABLED      true}
 
         ;; NOTE: electron, browser/mobile-app use different asset-paths.
@@ -54,7 +55,8 @@
 
                                 :externs  ["datascript/externs.js"
                                            "externs.js"]
-                                :warnings {:fn-deprecated false}}}
+                                :warnings {:fn-deprecated false
+                                           :redef false}}}
 
   :test {:target          :node-test
          :output-to       "static/tests.js"
@@ -86,7 +88,8 @@
                                   :output-feature-set :es-next
                                   :externs            ["datascript/externs.js"
                                                        "externs.js"]
-                                  :warnings           {:fn-deprecated false}}
+                                  :warnings           {:fn-deprecated false
+                                                       :redef false}}
                :devtools         {:before-load frontend.core/stop
                                   :after-load  frontend.core/start
                                   :preloads    [devtools.preload]}}

+ 74 - 0
src/main/frontend/db/model.cljs

@@ -409,6 +409,29 @@
                      f))
                  form))
 
+(defn get-sorted-page-block-ids
+  [page-id]
+  (let [root (db-utils/entity page-id)]
+    (loop [result []
+           children (sort-by-left (:block/_parent root) root)]
+      (if (seq children)
+        (let [child (first children)]
+          (recur (conj result (:db/id child))
+                 (concat
+                  (sort-by-left (:block/_parent child) child)
+                  (rest children))))
+        result))))
+
+(defn sort-page-random-blocks
+  "Blocks could be non consecutive."
+  [blocks]
+  (assert (every? #(= (:block/page %) (:block/page (first blocks))) blocks) "Blocks must to be in a same page.")
+  (let [page-id (:db/id (:block/page (first blocks)))
+        ;; TODO: there's no need to sort all the blocks
+        sorted-ids (get-sorted-page-block-ids page-id)
+        blocks-map (zipmap (map :db/id blocks) blocks)]
+    (keep blocks-map sorted-ids)))
+
 (defn has-children?
   ([block-id]
    (has-children? (conn/get-db) block-id))
@@ -584,6 +607,57 @@
               (recur parent)))
           false)))))
 
+(defn get-prev-sibling
+  [db id]
+  (when-let [e (d/entity db id)]
+    (let [left (:block/left e)]
+      (when (not= (:db/id left) (:db/id (:block/parent e)))
+        left))))
+
+(defn get-right-sibling
+  [db db-id]
+  (when-let [block (d/entity db db-id)]
+    (get-by-parent-&-left db
+                          (:db/id (:block/parent block))
+                          db-id)))
+
+(defn last-child-block?
+  "The child block could be collapsed."
+  [db parent-id child-id]
+  (when-let [child (d/entity db child-id)]
+    (cond
+      (= parent-id child-id)
+      true
+
+      (get-right-sibling db child-id)
+      false
+
+      :else
+      (last-child-block? db parent-id (:db/id (:block/parent child))))))
+
+(defn- consecutive-block?
+  [block-1 block-2]
+  (let [db (conn/get-db)
+        aux-fn (fn [block-1 block-2]
+                 (and (= (:block/page block-1) (:block/page block-2))
+                      (or
+                       ;; sibling or child
+                       (= (:db/id (:block/left block-2)) (:db/id block-1))
+                       (when-let [prev-sibling (get-prev-sibling db (:db/id block-2))]
+                         (last-child-block? db (:db/id prev-sibling) (:db/id block-1))))))]
+    (or (aux-fn block-1 block-2) (aux-fn block-2 block-1))))
+
+(defn get-non-consecutive-blocks
+  [blocks]
+  (vec
+   (keep-indexed
+    (fn [i _block]
+      (when (< (inc i) (count blocks))
+        (when-not (consecutive-block? (nth blocks i)
+                                      (nth blocks (inc i)))
+          (nth blocks i))))
+    blocks)))
+
 (defn- get-start-id-for-pagination-query
   [repo-url current-db {:keys [db-before tx-meta] :as tx-report}
    result outliner-op page-id block-id tx-block-ids]

+ 42 - 18
src/main/frontend/modules/outliner/core.cljs

@@ -99,7 +99,7 @@
 
   (-get-parent-id [this]
     (-> (get-in this [:data :block/parent])
-      (outliner-u/->block-id)))
+        (outliner-u/->block-id)))
 
   (-set-parent-id [this parent-id]
     (outliner-u/check-block-id parent-id)
@@ -107,7 +107,7 @@
 
   (-get-left-id [this]
     (-> (get-in this [:data :block/left])
-      (outliner-u/->block-id)))
+        (outliner-u/->block-id)))
 
   (-set-left-id [this left-id]
     (outliner-u/check-block-id left-id)
@@ -170,7 +170,7 @@
 
   (-del [this txs-state children?]
     (assert (ds/outliner-txs-state? txs-state)
-      "db should be satisfied outliner-tx-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)
@@ -192,7 +192,7 @@
                                                  (assoc :block/left parent))))
                                            immediate-children)))
                     txs))
-                  txs)]
+                txs)]
       (swap! txs-state concat txs)
       block-id))
 
@@ -209,12 +209,7 @@
 (defn get-right-sibling
   [db-id]
   (when db-id
-    (when-let [block (db/entity db-id)]
-      (db-model/get-by-parent-&-left (conn/get-db)
-                                     (:db/id (:block/parent block))
-                                     db-id))))
-
-
+    (db-model/get-right-sibling (conn/get-db) db-id)))
 
 (defn- assoc-level-aux
   [tree-vec children-key init-level]
@@ -285,13 +280,13 @@
     (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)))))
+      (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- page-first-child?
   [block]
@@ -573,6 +568,34 @@
                        (recur (:block/left (get id->blocks (:db/id block))))
                        (:db/id block)))})))
 
+(defn find-new-left
+  [block moved-ids target-block current-block sibling?]
+  (if (= (:db/id target-block) (:db/id (:block/left current-block)))
+    (if sibling?
+      (db/entity (last moved-ids))
+      target-block)
+    (let [left (db/entity (:db/id (:block/left block)))]
+      (if (contains? (set moved-ids) (:db/id left))
+        (find-new-left left moved-ids target-block current-block sibling?)
+        left))))
+
+(defn- fix-non-consecutive-blocks
+  [blocks target-block sibling?]
+  (let [page-blocks (group-by :block/page blocks)]
+    (->>
+     (mapcat (fn [[_page blocks]]
+               (let [blocks (db-model/sort-page-random-blocks blocks)
+                     non-consecutive-blocks (->> (conj (db-model/get-non-consecutive-blocks blocks) (last blocks))
+                                                 (util/distinct-by :db/id))]
+                 (when (seq non-consecutive-blocks)
+                   (mapv (fn [block]
+                           (when-let [right (get-right-sibling (:db/id block))]
+                             (when-let [new-left (find-new-left right (distinct (map :db/id blocks)) target-block block sibling?)]
+                               {:db/id      (:db/id right)
+                                :block/left (:db/id new-left)})))
+                         non-consecutive-blocks)))) page-blocks)
+     (remove nil?))))
+
 (defn move-blocks
   "Move `blocks` to `target-block` as siblings or children."
   [blocks target-block {:keys [sibling? outliner-op]}]
@@ -598,7 +621,8 @@
                                      (let [children-ids (mapcat #(db/get-block-children-ids (state/get-current-repo) (:block/uuid %)) blocks)]
                                        (map (fn [uuid] {:block/uuid uuid
                                                         :block/page target-page}) children-ids)))
-                  full-tx (util/concat-without-nil tx-data move-blocks-next-tx children-page-tx)
+                  fix-non-consecutive-tx (fix-non-consecutive-blocks blocks target-block sibling?)
+                  full-tx (util/concat-without-nil tx-data move-blocks-next-tx children-page-tx fix-non-consecutive-tx)
                   tx-meta (cond-> {:move-blocks (mapv :db/id blocks)
                                    :target (:db/id target-block)}
                             not-same-page?