mirror of
https://github.com/codex-team/editor.js
synced 2024-06-14 03:35:44 +02:00
Backspace on selected blocks (#536)
* initial * update * requested changes * Update src/components/modules/blockEvents.ts Co-Authored-By: khaydarov <murod.haydarov@inbox.ru> * minimized script * update
This commit is contained in:
parent
819719aadc
commit
4c9aa0fbd5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10378
package-lock.json
generated
Normal file
10378
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import Module from '../__module';
|
||||
import _ from '../utils';
|
||||
import CaretClass from './caret';
|
||||
|
||||
export default class BlockEvents extends Module {
|
||||
/**
|
||||
|
@ -78,8 +79,12 @@ export default class BlockEvents extends Module {
|
|||
*/
|
||||
this.Editor.BlockManager.clearFocused();
|
||||
|
||||
/** Clear Block selection and restore caret */
|
||||
this.Editor.BlockSelection.clearSelection(true);
|
||||
if (event.keyCode !== _.keyCodes.ENTER && event.keyCode !== _.keyCodes.BACKSPACE) {
|
||||
/**
|
||||
* Clear selection and restore caret before navigation
|
||||
*/
|
||||
this.Editor.BlockSelection.clearSelection(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,9 +231,24 @@ export default class BlockEvents extends Module {
|
|||
* @param {KeyboardEvent} event - keydown
|
||||
*/
|
||||
private backspace(event: KeyboardEvent): void {
|
||||
const BM = this.Editor.BlockManager;
|
||||
const currentBlock = this.Editor.BlockManager.currentBlock,
|
||||
tool = this.Editor.Tools.available[currentBlock.name];
|
||||
const { BlockManager, BlockSelection, Caret } = this.Editor;
|
||||
const currentBlock = BlockManager.currentBlock;
|
||||
const tool = this.Editor.Tools.available[currentBlock.name];
|
||||
|
||||
/**
|
||||
* Check if Block should be removed by current Backspace keydown
|
||||
*/
|
||||
if (currentBlock.selected || BlockManager.currentBlock.isEmpty) {
|
||||
if (BlockSelection.allBlocksSelected) {
|
||||
this.removeAllBlocks();
|
||||
} else {
|
||||
this.removeCurrentBlock();
|
||||
}
|
||||
|
||||
/** Clear selection */
|
||||
BlockSelection.clearSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't handle Backspaces when Tool sets enableLineBreaks to true.
|
||||
|
@ -238,45 +258,63 @@ export default class BlockEvents extends Module {
|
|||
return;
|
||||
}
|
||||
|
||||
const isFirstBlock = BM.currentBlockIndex === 0,
|
||||
canMergeBlocks = this.Editor.Caret.isAtStart && !isFirstBlock;
|
||||
const isFirstBlock = BlockManager.currentBlockIndex === 0;
|
||||
const canMergeBlocks = Caret.isAtStart && !isFirstBlock;
|
||||
|
||||
if (canMergeBlocks) {
|
||||
/**
|
||||
* preventing browser default behaviour
|
||||
*/
|
||||
event.preventDefault();
|
||||
|
||||
/**
|
||||
* Merge Blocks
|
||||
*/
|
||||
this.mergeBlocks();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove all selected Blocks
|
||||
*/
|
||||
private removeAllBlocks(): boolean {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
BlockManager.removeAllBlocks();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove current Block and sets Caret to the correct position
|
||||
*/
|
||||
private removeCurrentBlock(): boolean {
|
||||
const { BlockManager, Caret } = this.Editor;
|
||||
|
||||
/** If current Block is empty just remove this Block */
|
||||
if (this.Editor.BlockManager.currentBlock.isEmpty) {
|
||||
this.Editor.BlockManager.removeBlock();
|
||||
BlockManager.removeBlock();
|
||||
|
||||
/**
|
||||
* in case of last block deletion
|
||||
* Insert new initial empty block
|
||||
*/
|
||||
if (this.Editor.BlockManager.blocks.length === 0) {
|
||||
this.Editor.BlockManager.insert();
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of deletion first block we need to set caret to the current Block
|
||||
* After BlockManager removes the Block (which is current now),
|
||||
* pointer that references to the current Block, now points to the Next
|
||||
*/
|
||||
if (this.Editor.BlockManager.currentBlockIndex === 0) {
|
||||
this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);
|
||||
} else {
|
||||
this.Editor.Caret.navigatePrevious(true);
|
||||
}
|
||||
|
||||
this.Editor.Toolbar.close();
|
||||
return;
|
||||
/**
|
||||
* In case of deletion first block we need to set caret to the current Block
|
||||
* After BlockManager removes the Block (which is current now),
|
||||
* pointer that references to the current Block, now points to the Next
|
||||
*/
|
||||
if (BlockManager.currentBlockIndex === 0) {
|
||||
Caret.setToBlock(BlockManager.currentBlock);
|
||||
} else {
|
||||
Caret.setToBlock(BlockManager.previousBlock, CaretClass.positions.END);
|
||||
}
|
||||
|
||||
if (!canMergeBlocks) {
|
||||
return;
|
||||
}
|
||||
this.Editor.Toolbar.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// preventing browser default behaviour
|
||||
event.preventDefault();
|
||||
|
||||
const targetBlock = BM.getBlockByIndex(BM.currentBlockIndex - 1),
|
||||
blockToMerge = BM.currentBlock;
|
||||
/**
|
||||
* Merge current and previous Blocks if they have the same type
|
||||
*/
|
||||
private mergeBlocks() {
|
||||
const { BlockManager, Caret, Toolbar } = this.Editor;
|
||||
const targetBlock = BlockManager.getBlockByIndex(BlockManager.currentBlockIndex - 1),
|
||||
blockToMerge = BlockManager.currentBlock;
|
||||
|
||||
/**
|
||||
* Blocks that can be merged:
|
||||
|
@ -286,20 +324,20 @@ export default class BlockEvents extends Module {
|
|||
* other case will handle as usual ARROW LEFT behaviour
|
||||
*/
|
||||
if (blockToMerge.name !== targetBlock.name || !targetBlock.mergeable) {
|
||||
if (this.Editor.Caret.navigatePrevious()) {
|
||||
this.Editor.Toolbar.close();
|
||||
if (Caret.navigatePrevious()) {
|
||||
Toolbar.close();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.Editor.Caret.createShadow(targetBlock.pluginsContent);
|
||||
BM.mergeBlocks(targetBlock, blockToMerge)
|
||||
Caret.createShadow(targetBlock.pluginsContent);
|
||||
BlockManager.mergeBlocks(targetBlock, blockToMerge)
|
||||
.then( () => {
|
||||
/** Restore caret position after merge */
|
||||
this.Editor.Caret.restoreCaret(targetBlock.pluginsContent as HTMLElement);
|
||||
Caret.restoreCaret(targetBlock.pluginsContent as HTMLElement);
|
||||
targetBlock.pluginsContent.normalize();
|
||||
this.Editor.Toolbar.close();
|
||||
Toolbar.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -240,6 +240,21 @@ export default class BlockManager extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attention!
|
||||
* After removing insert new initial typed Block and focus on it
|
||||
* Removes all blocks
|
||||
*/
|
||||
public removeAllBlocks(): void {
|
||||
for (let index = this.blocks.length - 1; index >= 0; index--) {
|
||||
this._blocks.remove(index);
|
||||
}
|
||||
|
||||
this.currentBlockIndex = -1;
|
||||
this.insert();
|
||||
this.currentBlock.firstInput.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Split current Block
|
||||
* 1. Extract content from Caret position to the Block`s end
|
||||
|
|
|
@ -12,6 +12,38 @@ import $ from '../dom';
|
|||
import SelectionUtils from '../selection';
|
||||
|
||||
export default class BlockSelection extends Module {
|
||||
|
||||
/**
|
||||
* Sanitizer Config
|
||||
* @return {SanitizerConfig}
|
||||
*/
|
||||
private get sanitizerConfig() {
|
||||
return {
|
||||
p: {},
|
||||
h1: {},
|
||||
h2: {},
|
||||
h3: {},
|
||||
h4: {},
|
||||
h5: {},
|
||||
h6: {},
|
||||
ol: {},
|
||||
ul: {},
|
||||
li: {},
|
||||
br: true,
|
||||
img: {
|
||||
src: true,
|
||||
width: true,
|
||||
height: true,
|
||||
},
|
||||
a: {
|
||||
href: true,
|
||||
},
|
||||
b: {},
|
||||
i: {},
|
||||
u: {},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag used to define block selection
|
||||
* First CMD+A defines it as true and then second CMD+A selects all Blocks
|
||||
|
@ -25,6 +57,26 @@ export default class BlockSelection extends Module {
|
|||
*/
|
||||
private selection: SelectionUtils;
|
||||
|
||||
/**
|
||||
* Flag that identifies all Blocks selection
|
||||
* @return {boolean}
|
||||
*/
|
||||
public get allBlocksSelected(): boolean {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
return BlockManager.blocks.every( (block) => block.selected === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected all blocks
|
||||
* @param {boolean} state
|
||||
*/
|
||||
public set allBlocksSelected(state: boolean) {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
BlockManager.blocks.forEach( (block) => block.selected = state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Module Preparation
|
||||
* Registers Shortcuts CMD+A and CMD+C
|
||||
|
@ -57,15 +109,15 @@ export default class BlockSelection extends Module {
|
|||
*/
|
||||
public clearSelection(restoreSelection = false) {
|
||||
const { BlockManager } = this.Editor;
|
||||
const anyBlockSelected = BlockManager.blocks.findIndex( (block) => block.selected === true) !== -1;
|
||||
const anyBlockSelected = BlockManager.blocks.some( (block) => block.selected === true);
|
||||
|
||||
this.allBlocksSelected = false;
|
||||
this.needToSelectAll = false;
|
||||
|
||||
if (!anyBlockSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.needToSelectAll = false;
|
||||
BlockManager.blocks.forEach( (block) => block.selected = false);
|
||||
|
||||
/**
|
||||
* restore selection when Block is already selected
|
||||
* but someone tries to write something.
|
||||
|
@ -132,7 +184,7 @@ export default class BlockSelection extends Module {
|
|||
private selectAllBlocks() {
|
||||
const { BlockManager } = this.Editor;
|
||||
|
||||
BlockManager.blocks.forEach( (block) => block.selected = true);
|
||||
this.allBlocksSelected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,35 +214,4 @@ export default class BlockSelection extends Module {
|
|||
|
||||
block.selected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizer Config
|
||||
* @return {SanitizerConfig}
|
||||
*/
|
||||
private get sanitizerConfig() {
|
||||
return {
|
||||
p: {},
|
||||
h1: {},
|
||||
h2: {},
|
||||
h3: {},
|
||||
h4: {},
|
||||
h5: {},
|
||||
h6: {},
|
||||
ol: {},
|
||||
ul: {},
|
||||
li: {},
|
||||
br: true,
|
||||
img: {
|
||||
src: true,
|
||||
width: true,
|
||||
height: true,
|
||||
},
|
||||
a: {
|
||||
href: true,
|
||||
},
|
||||
b: {},
|
||||
i: {},
|
||||
u: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,6 +371,7 @@ export default class Caret extends Module {
|
|||
|
||||
if (force) {
|
||||
this.setToBlock( previousContentfulBlock, Caret.positions.END );
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.isAtStart) {
|
||||
|
|
Loading…
Reference in a new issue