diff --git a/e2e-tests/basic.spec.ts b/e2e-tests/basic.spec.ts index 3987ef7bae..515e0c6da2 100644 --- a/e2e-tests/basic.spec.ts +++ b/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) }) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 6226867d02..da5e7edf46 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/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))))))