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:
Murod Khaydarov 2018-11-26 09:34:23 +03:00 committed by GitHub
parent 819719aadc
commit 4c9aa0fbd5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 10611 additions and 158 deletions

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -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: {},
};
}
}

View file

@ -371,6 +371,7 @@ export default class Caret extends Module {
if (force) {
this.setToBlock( previousContentfulBlock, Caret.positions.END );
return true;
}
if (this.isAtStart) {