Skip to content

Commit 29d68ec

Browse files
authored
fix(block-events): caret losing after backspace after nested list (#2723)
* feat: Fix caret loss after Backspace at the start of block when previous block is not convertible * fix create shadow caret * fix: remove unnecessary blank line in blockEvents.ts * fix: pass event object to slashPressed method in blockEvents.ts * fix eslint
1 parent d18eeb5 commit 29d68ec

File tree

4 files changed

+96
-9
lines changed

4 files changed

+96
-9
lines changed

docs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- `Fix` – Unwanted scroll on first typing on iOS devices
1414
- `Fix` - Unwanted soft line break on Enter press after period and space (". |") on iOS devices
1515
- `Fix` - Caret lost after block conversion on mobile devices.
16+
- `Fix` - Caret lost after Backspace at the start of block when previoius block is not convertable
1617
- `Improvement` - The API `blocks.convert()` now returns the new block API
1718
- `Improvement` - The API `caret.setToBlock()` now can accept either BlockAPI or block index or block id
1819
- `New`*Menu Config* – New item type – HTML

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@editorjs/editorjs",
3-
"version": "2.30.0-rc.9",
3+
"version": "2.30.0-rc.10",
44
"description": "Editor.js — Native JS, based on API and Open Source",
55
"main": "dist/editorjs.umd.js",
66
"module": "dist/editorjs.mjs",

src/components/modules/blockEvents.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export default class BlockEvents extends Module {
6060
* @todo probably using "beforeInput" event would be better here
6161
*/
6262
if (event.key === '/' && !event.ctrlKey && !event.metaKey) {
63-
this.slashPressed();
63+
this.slashPressed(event);
6464
}
6565

6666
/**
@@ -233,8 +233,10 @@ export default class BlockEvents extends Module {
233233

234234
/**
235235
* '/' keydown inside a Block
236+
*
237+
* @param event - keydown
236238
*/
237-
private slashPressed(): void {
239+
private slashPressed(event: KeyboardEvent): void {
238240
const currentBlock = this.Editor.BlockManager.currentBlock;
239241
const canOpenToolbox = currentBlock.isEmpty;
240242

@@ -395,7 +397,7 @@ export default class BlockEvents extends Module {
395397
return;
396398
}
397399

398-
const bothBlocksMergeable = areBlocksMergeable(currentBlock, previousBlock);
400+
const bothBlocksMergeable = areBlocksMergeable(previousBlock, currentBlock);
399401

400402
/**
401403
* If Blocks could be merged, do it
@@ -499,7 +501,7 @@ export default class BlockEvents extends Module {
499501
private mergeBlocks(targetBlock: Block, blockToMerge: Block): void {
500502
const { BlockManager, Caret, Toolbar } = this.Editor;
501503

502-
Caret.createShadow(targetBlock.pluginsContent);
504+
Caret.createShadow(targetBlock.lastInput);
503505

504506
BlockManager
505507
.mergeBlocks(targetBlock, blockToMerge)

test/cypress/tests/modules/BlockEvents/Backspace.cy.ts

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type EditorJS from '../../../../../types/index';
22
import Chainable = Cypress.Chainable;
33
import { SimpleHeader } from '../../../fixtures/tools/SimpleHeader';
4+
import type { ConversionConfig } from '../../../../../types/index';
45

56

67
/**
@@ -425,11 +426,11 @@ describe('Backspace keydown', function () {
425426
.should('not.have.class', 'ce-toolbar--opened');
426427
});
427428

428-
it('should simply set Caret to the end of the previous Block if Caret at the start of the Block but Blocks are not mergeable. Also, should close the Toolbox.', function () {
429+
it('should simply set Caret to the end of the previous Block if Caret at the start of the Block but Blocks are not mergeable (target Bock is lack of merge() and conversionConfig). Also, should close the Toolbox.', function () {
429430
/**
430-
* Mock of tool without merge method
431+
* Mock of tool without merge() method
431432
*/
432-
class ExampleOfUnmergeableTool {
433+
class UnmergeableToolWithoutConversionConfig {
433434
/**
434435
* Render method mock
435436
*/
@@ -452,7 +453,90 @@ describe('Backspace keydown', function () {
452453

453454
cy.createEditor({
454455
tools: {
455-
code: ExampleOfUnmergeableTool,
456+
code: UnmergeableToolWithoutConversionConfig,
457+
},
458+
data: {
459+
blocks: [
460+
{
461+
type: 'code',
462+
data: {},
463+
},
464+
{
465+
type: 'paragraph',
466+
data: {
467+
text: 'Second block',
468+
},
469+
},
470+
],
471+
},
472+
});
473+
474+
cy.get('[data-cy=editorjs]')
475+
.find('.ce-paragraph')
476+
.last()
477+
.click()
478+
.type('{home}')
479+
.type('{backspace}');
480+
481+
cy.get('[data-cy=editorjs]')
482+
.find('[data-cy=unmergeable-tool]')
483+
.as('firstBlock');
484+
485+
/**
486+
* Caret is set to the previous Block
487+
*/
488+
cy.window()
489+
.then((window) => {
490+
const selection = window.getSelection();
491+
const range = selection.getRangeAt(0);
492+
493+
cy.get('@firstBlock').should(($div) => {
494+
expect($div[0].contains(range.startContainer)).to.be.true;
495+
});
496+
});
497+
});
498+
499+
it('should simply set Caret to the end of the previous Block if Caret at the start of the Block but Blocks are not mergeable (target Bock is lack of merge() but has the conversionConfig). Also, should close the Toolbox.', function () {
500+
/**
501+
* Mock of tool without merge() method
502+
*/
503+
class UnmergeableToolWithConversionConfig {
504+
/**
505+
* Render method mock
506+
*/
507+
public render(): HTMLElement {
508+
const container = document.createElement('div');
509+
510+
container.dataset.cy = 'unmergeable-tool';
511+
container.contentEditable = 'true';
512+
container.innerHTML = 'Unmergeable not empty tool';
513+
514+
return container;
515+
}
516+
517+
/**
518+
* Saving logic is not necessary for this test
519+
*/
520+
public save(): { key: string } {
521+
return {
522+
key: 'value',
523+
};
524+
}
525+
526+
/**
527+
* Mock of the conversionConfig
528+
*/
529+
public static get conversionConfig(): ConversionConfig {
530+
return {
531+
export: 'key',
532+
import: 'key',
533+
};
534+
}
535+
}
536+
537+
cy.createEditor({
538+
tools: {
539+
code: UnmergeableToolWithConversionConfig,
456540
},
457541
data: {
458542
blocks: [

0 commit comments

Comments
 (0)