diff --git a/src/editor/block/commands.js b/src/editor/block/commands.js index fe9bf3bb..f67ccbef 100644 --- a/src/editor/block/commands.js +++ b/src/editor/block/commands.js @@ -323,6 +323,46 @@ export function triggerCurrenciesLoaded(state, dispatch) { } export const deleteBlock = (editor) => ({state, dispatch}) => { + const range = state.selection.asSingle().ranges[0] + const blocks = state.facet(blockState) + let block + let nextBlock + for (let i = 0; i < blocks.length; i++) { + block = blocks[i] + if (block.range.from <= range.head && block.range.to >= range.head) { + if (i < blocks.length - 1) { + nextBlock = blocks[i + 1] + } + break + } + } + + let replace = "" + let newSelection + + if (blocks.length == 1) { + replace = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect) + newSelection = replace.length + } else if (!nextBlock) { + // if it's the last block, the cursor should go at the en of the previous block + newSelection = block.delimiter.from + } else { + // if there is a next block, we want the cursor to be at the beginning of that block + newSelection = block.delimiter.from + (nextBlock.delimiter.to - nextBlock.delimiter.from) + } + + dispatch(state.update({ + changes: { + from: block.range.from, + to: block.range.to, + insert: replace, + }, + selection: EditorSelection.cursor(newSelection), + annotations: [heynoteEvent.of(DELETE_BLOCK)], + })) +} + +export const deleteBlockSetCursorPreviousBlock = (editor) => ({state, dispatch}) => { const block = getActiveNoteBlock(state) const blocks = state.facet(blockState) let replace = "" diff --git a/src/editor/editor.js b/src/editor/editor.js index 9539850d..d792da24 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -238,6 +238,13 @@ export class HeynoteEditor { return this.view.state.selection.main.head } + setCursorPosition(position) { + this.view.dispatch({ + selection: {anchor: position, head: position}, + scrollIntoView: true, + }) + } + focus() { this.view.focus() } diff --git a/tests/delete-block.spec.js b/tests/delete-block.spec.js new file mode 100644 index 00000000..8599eb39 --- /dev/null +++ b/tests/delete-block.spec.js @@ -0,0 +1,44 @@ +import {expect, test} from "@playwright/test"; +import {HeynotePage} from "./test-utils.js"; + +import { AUTO_SAVE_INTERVAL } from "../src/common/constants.js" +import { NoteFormat } from "../src/common/note-format.js" + + +let heynotePage + +test.beforeEach(async ({page}) => { + heynotePage = new HeynotePage(page) + await heynotePage.goto() + + expect((await heynotePage.getBlocks()).length).toBe(1) + await heynotePage.setContent(` +∞∞∞text +Block A +∞∞∞markdown +Block B +∞∞∞text +Block C`) + await page.waitForTimeout(100) +}) + +test("delete first block", async ({page}) => { + await heynotePage.setCursorPosition(10) + await page.locator("body").press(heynotePage.agnosticKey("Mod+Shift+D")) + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(13) +}) + +test("delete middle block", async ({page}) => { + await heynotePage.setCursorPosition(32) + await page.locator("body").press(heynotePage.agnosticKey("Mod+Shift+D")) + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(25) +}) + +test("delete last block", async ({page}) => { + await heynotePage.setCursorPosition(52) + await page.locator("body").press(heynotePage.agnosticKey("Mod+Shift+D")) + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(36) +}) diff --git a/tests/move-block.spec.js b/tests/move-block.spec.js index ec909c82..20e84e5b 100644 --- a/tests/move-block.spec.js +++ b/tests/move-block.spec.js @@ -25,15 +25,17 @@ Block C`) // check that visual block layers are created await expect(page.locator("css=.heynote-blocks-layer > div")).toHaveCount(3) -}); - -test("move block to other buffer", async ({page}) => { + // create secondary buffer await heynotePage.saveBuffer("other.txt", ` ∞∞∞text-a First block ∞∞∞math Second block`) +}); + + +test("move block to other buffer", async ({page}) => { await page.locator("body").press(heynotePage.agnosticKey("Mod+S")) await page.waitForTimeout(50) await page.locator("body").press("Enter") @@ -62,11 +64,6 @@ Block C`) test("move block to other open/cached buffer", async ({page}) => { - await heynotePage.saveBuffer("other.txt", ` -∞∞∞text-a -First block -∞∞∞math -Second block`) await page.locator("body").press(heynotePage.agnosticKey("Mod+P")) await page.locator("body").press("Enter") await page.waitForTimeout(50) @@ -99,3 +96,30 @@ Block C`) }) +test("cursor position after moving first block", async ({page}) => { + await heynotePage.setCursorPosition(10) + expect(await heynotePage.getCursorPosition()).toBe(10) + await page.locator("body").press(heynotePage.agnosticKey("Mod+S")) + await page.waitForTimeout(50) + await page.locator("body").press("Enter") + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(9) +}) + +test("cursor position after moving middle block", async ({page}) => { + await heynotePage.setCursorPosition(28) + await page.locator("body").press(heynotePage.agnosticKey("Mod+S")) + await page.waitForTimeout(50) + await page.locator("body").press("Enter") + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(25) +}) + +test("cursor position after moving last block", async ({page}) => { + await heynotePage.setCursorPosition(48) + await page.locator("body").press(heynotePage.agnosticKey("Mod+S")) + await page.waitForTimeout(50) + await page.locator("body").press("Enter") + await page.waitForTimeout(50) + expect(await heynotePage.getCursorPosition()).toBe(32) +}) diff --git a/tests/test-utils.js b/tests/test-utils.js index f2b1a4c0..80f8c194 100644 --- a/tests/test-utils.js +++ b/tests/test-utils.js @@ -48,6 +48,10 @@ export class HeynotePage { return await this.page.evaluate(() => window._heynote_editor.getCursorPosition()) } + async setCursorPosition(position) { + await this.page.evaluate((position) => window._heynote_editor.setCursorPosition(position), position) + } + async getBlockContent(blockIndex) { const blocks = await this.getBlocks() const content = await this.getContent()