Position the cursor at the beginning of the next block when a block is deleted

This also changes the behavior when blocks are moved.
Add tests for the deleteBlock command.
This commit is contained in:
Jonatan Heyman 2025-01-09 14:04:02 +01:00
parent 03ec7a4867
commit 52a6c444eb
5 changed files with 127 additions and 8 deletions

View File

@ -323,6 +323,46 @@ export function triggerCurrenciesLoaded(state, dispatch) {
} }
export const deleteBlock = (editor) => ({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 block = getActiveNoteBlock(state)
const blocks = state.facet(blockState) const blocks = state.facet(blockState)
let replace = "" let replace = ""

View File

@ -238,6 +238,13 @@ export class HeynoteEditor {
return this.view.state.selection.main.head return this.view.state.selection.main.head
} }
setCursorPosition(position) {
this.view.dispatch({
selection: {anchor: position, head: position},
scrollIntoView: true,
})
}
focus() { focus() {
this.view.focus() this.view.focus()
} }

View File

@ -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)
})

View File

@ -25,15 +25,17 @@ Block C`)
// check that visual block layers are created // check that visual block layers are created
await expect(page.locator("css=.heynote-blocks-layer > div")).toHaveCount(3) await expect(page.locator("css=.heynote-blocks-layer > div")).toHaveCount(3)
});
// create secondary buffer
test("move block to other buffer", async ({page}) => {
await heynotePage.saveBuffer("other.txt", ` await heynotePage.saveBuffer("other.txt", `
text-a text-a
First block First block
math math
Second block`) Second block`)
});
test("move block to other buffer", async ({page}) => {
await page.locator("body").press(heynotePage.agnosticKey("Mod+S")) await page.locator("body").press(heynotePage.agnosticKey("Mod+S"))
await page.waitForTimeout(50) await page.waitForTimeout(50)
await page.locator("body").press("Enter") await page.locator("body").press("Enter")
@ -62,11 +64,6 @@ Block C`)
test("move block to other open/cached buffer", async ({page}) => { 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(heynotePage.agnosticKey("Mod+P"))
await page.locator("body").press("Enter") await page.locator("body").press("Enter")
await page.waitForTimeout(50) 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)
})

View File

@ -48,6 +48,10 @@ export class HeynotePage {
return await this.page.evaluate(() => window._heynote_editor.getCursorPosition()) 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) { async getBlockContent(blockIndex) {
const blocks = await this.getBlocks() const blocks = await this.getBlocks()
const content = await this.getContent() const content = await this.getContent()