Răsfoiți Sursa

fix: broken outliner structure when Backspace at the beginning (#9125)

* fix: broken outliner structure when DELETE at the beginning

related to #8974

* fix: 'Delete' key deletes entire set of blocks

close #9128

---------

Co-authored-by: Mega Yu <[email protected]>
Tienson Qin 2 ani în urmă
părinte
comite
a8013a5288
2 a modificat fișierele cu 83 adăugiri și 21 ștergeri
  1. 50 0
      e2e-tests/basic.spec.ts
  2. 33 21
      src/main/frontend/handler/editor.cljs

+ 50 - 0
e2e-tests/basic.spec.ts

@@ -169,6 +169,56 @@ test('delete and backspace', async ({ page, block }) => {
   await page.waitForTimeout(100)
   expect(await page.inputValue('textarea >> nth=0')).toBe('tetestno refno refhas a ref')
   await expect(page.locator('.warning')).toHaveCount(1)
+
+  // backspace across blocks special case
+  // the current block has refs and the prev block has no refs, and the current block and the prev block has different parent block
+  // after backspace, the current block indent
+  await page.keyboard.press(modKey + '+z')
+  await page.waitForTimeout(100)
+  await block.clickNext()
+  await block.mustFill('1')
+  await page.keyboard.press('Enter')
+  await block.indent()
+  await block.mustFill('1.1')
+  await block.clickNext()
+  await block.mustFill('ref')
+  await page.keyboard.press(modKey + '+c')
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Enter')
+  await page.keyboard.press(modKey + '+v')
+  await page.waitForTimeout(100)
+  await page.keyboard.press('ArrowUp', { delay: 50 })
+  await page.keyboard.press('Home')
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Backspace', { delay: 50 })
+  await page.waitForTimeout(100)
+  await expect(page.locator('.warning')).toHaveCount(0)
+  expect(await page.inputValue('textarea >> nth=0')).toBe('1.1ref')
+  expect(await block.selectionStart()).toBe('1.1'.length)
+  // after backspace, the current block unindent
+  await page.keyboard.press(modKey + '+z')
+  await page.waitForTimeout(100)
+  await block.indent()
+  await block.indent()
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Backspace', { delay: 50 })
+  await page.waitForTimeout(100)
+  await expect(page.locator('.warning')).toHaveCount(0)
+  expect(await page.inputValue('textarea >> nth=0')).toBe('1.1ref')
+  expect(await block.selectionStart()).toBe('1.1'.length)
+
+  // delete across blocks special case
+  // the current block has no refs, and the current block and the next block has different parent block
+  // after delete, the next block unindent
+  await page.keyboard.press(modKey + '+z')
+  await page.waitForTimeout(100)
+  await page.keyboard.press('ArrowUp', { delay: 50 })
+  await page.keyboard.press('End')
+  await page.waitForTimeout(100)
+  await page.keyboard.press('Delete')
+  await page.waitForTimeout(100)
+  await expect(page.locator('.warning')).toHaveCount(0)
+  expect(await block.selectionStart()).toBe('1.1'.length)
 })
 
 

+ 33 - 21
src/main/frontend/handler/editor.cljs

@@ -834,28 +834,38 @@
                        ;; it's possible to find a block not belong to the same page of current editing block
                        sibling-block (util/get-prev-block-non-collapsed-non-embed block-parent)
                        delete_prev? (and (not (block-has-no-ref? (:db/id block)))
-                                         (block-has-no-ref? [:block/uuid (uuid (dom/attr sibling-block "blockid"))]))
+                                         (block-has-no-ref? [:block/uuid (uuid (dom/attr sibling-block "blockid"))])
+                                         (not (string/blank? value))) ; it doesn't make sense to preserve the block ref for totally different block
                        {:keys [prev-block new-content pos]} (move-to-prev-block repo sibling-block format id value (not delete_prev?))
                        concat-prev-block? (boolean (and prev-block new-content))
-                       save-page? (= (:db/id (:block/page prev-block)) page-id)
+                       same-page? (= (:db/id (:block/page prev-block)) page-id)
                        transact-opts (cond->
                                        {:outliner-op :delete-block}
                                        concat-prev-block?
                                        (assoc :concat-data
                                               {:last-edit-block (:block/uuid block)}))]
-                   (if (and delete_prev? save-page?)
-                     (let [block (assoc block :block/left (:block/left prev-block))
-                           input (gdom/getElement id)]
-                       (outliner-tx/transact! transact-opts
-                                              (delete-block-aux! prev-block false)
-                                              (save-block! repo block new-content))
-                       (state/set-edit-content! id new-content)
-                       (cursor/move-cursor-to input pos))
-                     (outliner-tx/transact! transact-opts
-                                            (when concat-prev-block?
-                                              (save-block! repo prev-block new-content))
-                                            (delete-block-aux! block delete-children?)))
-                   ))))))))
+                   (if (and delete_prev? same-page?)
+                     (let [right (when-not (= (:block/parent block)
+                                              (:block/parent prev-block))
+                                   (when-let [right-id (some-> (tree/-get-right (outliner-core/block block))
+                                                         tree/-get-id)]
+                                     {:block/uuid right-id
+                                      :block/left (:block/left block)}))
+                           additional-tx (conj [{:db/id (:db/id block)
+                                                 :block/left (:block/left prev-block)
+                                                 :block/parent (:block/parent prev-block)}] right)
+                           transact-opts (assoc transact-opts :additional-tx additional-tx)]
+                       (outliner-tx/transact!
+                         transact-opts
+                         (delete-block-aux! prev-block false)
+                         (save-block! repo block new-content))
+                       (edit-block! block pos id {:custom-content new-content
+                                                  :move-cursor? true}))
+                     (outliner-tx/transact!
+                       transact-opts
+                       (when concat-prev-block?
+                         (save-block! repo prev-block new-content))
+                       (delete-block-aux! block delete-children?)))))))))))
    (state/set-editor-op! nil)))
 
 (defn delete-blocks!
@@ -2686,15 +2696,17 @@
 
       (and next-block (block-has-no-ref? (:db/id current-block)))
       (let [edit-block (state/get-edit-block)
+            new-content (str value (:block/content next-block))
             transact-opts {:outliner-op :delete-block
                            :concat-data {:last-edit-block (:block/uuid edit-block)
-                                         :end? true}}
-            new-content (str value "" (:block/content next-block))
-            next-block (assoc next-block :block/left (:block/left current-block))
+                                         :end? true}
+                           :additional-tx [{:db/id (:db/id next-block)
+                                            :block/left (:block/left current-block)
+                                            :block/parent (:block/parent current-block)}]}
             repo (state/get-current-repo)]
         (outliner-tx/transact! transact-opts
-                               (delete-block-aux! edit-block false)
-                               (save-block! repo next-block new-content))
+          (delete-block-aux! edit-block false)
+          (save-block! repo next-block new-content))
         (edit-block! next-block current-pos (:block/uuid next-block)))
 
       :else
@@ -2729,7 +2741,7 @@
               custom-query? (get-in editor-state [:config :custom-query?])]
           (when-not custom-query?
             (delete-concat current-block input current-pos value)))
-            
+
         :else
         (delete-and-update input current-pos (inc current-pos))))))