Pārlūkot izejas kodu

fix: editor freeze when cut and paste blocks at the bottom

Tienson Qin 3 gadi atpakaļ
vecāks
revīzija
274639fe78

+ 24 - 0
e2e-tests/editor.spec.ts

@@ -168,3 +168,27 @@ test.skip('next block and cursor position', async ({ page, block }) => {
 //     await page.keyboard.press('Control+Shift+v')
 //     await page.keyboard.press('Control+Shift+v')
 //   }
 //   }
 // })
 // })
+
+test('cut blocks and paste', async ({ page, block }) => {
+  await createRandomPage(page)
+
+  for (let i = 0; i < 5; i++) {
+    await block.mustType(i.toString())
+    await block.enterNext()
+  }
+
+  // shift+up select 3 blocks
+  await page.keyboard.down('Shift')
+  await page.keyboard.press('ArrowUp')
+  await page.keyboard.press('ArrowUp')
+  await page.keyboard.press('ArrowUp')
+  await page.keyboard.up('Shift')
+
+  await block.waitForSelectedBlocks(3)
+
+  await page.keyboard.press('Meta+x')
+
+  await page.keyboard.press('Meta+v')
+
+  await expect(page.locator('.ls-block')).toHaveCount(6, { timeout: 1000 })
+})

+ 32 - 30
src/main/frontend/handler/editor.cljs

@@ -885,23 +885,20 @@
    (state/set-editor-op! nil)))
    (state/set-editor-op! nil)))
 
 
 (defn delete-blocks!
 (defn delete-blocks!
-  [repo dom-blocks]
-  (let [block-uuids (distinct (map #(uuid (dom/attr % "blockid")) dom-blocks))]
-    (when (seq block-uuids)
-      (let [uuid->dom-block (zipmap block-uuids dom-blocks)
-            lookup-refs (map (fn [id] [:block/uuid id]) block-uuids)
-            blocks (db/pull-many repo '[*] lookup-refs)
-            block (first blocks)
-            block-parent (get uuid->dom-block (:block/uuid block))
-            sibling-block (when block-parent (util/get-prev-block-non-collapsed-non-embed block-parent))]
-        (outliner-tx/transact!
-          {:outliner-op :delete-blocks}
-          (outliner-core/delete-blocks! blocks {}))
-        (when sibling-block
-          (move-to-prev-block repo sibling-block
-                              (:block/format block)
-                              (dom/attr sibling-block "id")
-                              ""))))))
+  [repo block-uuids blocks dom-blocks]
+  (when (seq block-uuids)
+    (let [uuid->dom-block (zipmap block-uuids dom-blocks)
+          block (first blocks)
+          block-parent (get uuid->dom-block (:block/uuid block))
+          sibling-block (when block-parent (util/get-prev-block-non-collapsed-non-embed block-parent))]
+      (outliner-tx/transact!
+        {:outliner-op :delete-blocks}
+        (outliner-core/delete-blocks! blocks {}))
+      (when sibling-block
+        (move-to-prev-block repo sibling-block
+                            (:block/format block)
+                            (dom/attr sibling-block "id")
+                            "")))))
 
 
 (defn- batch-set-block-property!
 (defn- batch-set-block-property!
   "col: a collection of [block-id property-key property-value]."
   "col: a collection of [block-id property-key property-value]."
@@ -1019,9 +1016,8 @@
   []
   []
   (when-let [blocks (seq (state/get-selection-blocks))]
   (when-let [blocks (seq (state/get-selection-blocks))]
     (let [repo (state/get-current-repo)
     (let [repo (state/get-current-repo)
-          ids (->> (distinct (map #(when-let [id (dom/attr % "blockid")]
-                                     (uuid id)) blocks))
-                   (remove nil?))
+          ids (distinct (keep #(when-let [id (dom/attr % "blockid")]
+                                 (uuid id)) blocks))
           content (compose-copied-blocks-contents repo ids)
           content (compose-copied-blocks-contents repo ids)
           block (db/entity [:block/uuid (first ids)])]
           block (db/entity [:block/uuid (first ids)])]
       (when block
       (when block
@@ -1097,12 +1093,16 @@
   (when copy? (copy-selection-blocks))
   (when copy? (copy-selection-blocks))
   (when-let [blocks (seq (get-selected-blocks))]
   (when-let [blocks (seq (get-selected-blocks))]
     ;; remove embeds, references and queries
     ;; remove embeds, references and queries
-    (let [blocks (remove (fn [block]
+    (let [dom-blocks (remove (fn [block]
                            (or (= "true" (dom/attr block "data-transclude"))
                            (or (= "true" (dom/attr block "data-transclude"))
                                (= "true" (dom/attr block "data-query")))) blocks)]
                                (= "true" (dom/attr block "data-query")))) blocks)]
-      (when (seq blocks)
-        (let [repo (state/get-current-repo)]
-          (delete-blocks! repo blocks))))))
+      (when (seq dom-blocks)
+        (let [repo (state/get-current-repo)
+              block-uuids (distinct (map #(uuid (dom/attr % "blockid")) dom-blocks))
+              lookup-refs (map (fn [id] [:block/uuid id]) block-uuids)
+              blocks (db/pull-many repo '[*] lookup-refs)]
+          (state/set-copied-full-blocks nil blocks)
+          (delete-blocks! repo block-uuids blocks dom-blocks))))))
 
 
 (def url-regex
 (def url-regex
   "Didn't use link/plain-link as it is incorrectly detects words as urls."
   "Didn't use link/plain-link as it is incorrectly detects words as urls."
@@ -1236,6 +1236,7 @@
     (let [repo (state/get-current-repo)
     (let [repo (state/get-current-repo)
           ;; TODO: support org mode
           ;; TODO: support org mode
           md-content (compose-copied-blocks-contents repo [block-id])]
           md-content (compose-copied-blocks-contents repo [block-id])]
+      (state/set-copied-full-blocks md-content [block])
       (common-handler/copy-to-clipboard-without-id-property! (:block/format block) md-content)
       (common-handler/copy-to-clipboard-without-id-property! (:block/format block) md-content)
       (delete-block-aux! block true))))
       (delete-block-aux! block true))))
 
 
@@ -2867,7 +2868,7 @@
     (if (seq ids)
     (if (seq ids)
       (let [blocks (db/get-block-and-children repo (first ids))
       (let [blocks (db/get-block-and-children repo (first ids))
             result (vec (concat result blocks))]
             result (vec (concat result blocks))]
-        (recur (remove (set (map :block/uuid result)) ids) result))
+        (recur (remove (set (map :block/uuid result)) (rest ids)) result))
       result)))
       result)))
 
 
 (defn- paste-text
 (defn- paste-text
@@ -2877,11 +2878,12 @@
         input (state/get-input)
         input (state/get-input)
         *stop-event? (atom true)]
         *stop-event? (atom true)]
     (cond
     (cond
-      (and (seq copied-block-ids)
-           (:copy/content copied-blocks)
-           (not (string/blank? text))
-           (= (string/replace (string/trim text) "\r" "")
-              (string/replace (string/trim (:copy/content copied-blocks)) "\r" "")))
+      (or (seq copied-block-ids)
+          (seq (:copy/full-blocks copied-blocks))
+          (and text
+               (:copy/content copied-blocks)
+               (= (string/replace (string/trim text) "\r" "")
+                  (string/replace (string/trim (:copy/content copied-blocks)) "\r" ""))))
       (let [blocks (or
       (let [blocks (or
                     (:copy/full-blocks copied-blocks)
                     (:copy/full-blocks copied-blocks)
                     (get-all-blocks-by-ids (state/get-current-repo) copied-block-ids))]
                     (get-all-blocks-by-ids (state/get-current-repo) copied-block-ids))]

+ 5 - 0
src/main/frontend/state.cljs

@@ -1477,6 +1477,11 @@
                             :copy/block-ids ids
                             :copy/block-ids ids
                             :copy/full-blocks nil}))
                             :copy/full-blocks nil}))
 
 
+(defn set-copied-full-blocks
+  [content blocks]
+  (set-state! :copy/blocks {:copy/content content
+                            :copy/full-blocks blocks}))
+
 (defn set-copied-full-blocks!
 (defn set-copied-full-blocks!
   [blocks]
   [blocks]
   (set-state! [:copy/blocks :copy/full-blocks] blocks))
   (set-state! [:copy/blocks :copy/full-blocks] blocks))