[Shortcuts]: CMD+X (#592)

* [Shortcuts]: CMD+X

* shortcuts must be in BlockManager

* small code improvements

* compact bundle

* insert new block in case of cmd+x

* prevent default

* suggested changes
This commit is contained in:
Murod Khaydarov 2019-01-11 23:53:36 +03:00 committed by GitHub
parent bc3341bfa1
commit d00412e1df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 91 deletions

File diff suppressed because one or more lines are too long

1
dist/codex-editor.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,9 @@
# Changelog
### 2.2.23 changelog
- `New` *Shortcuts — copy and cut Blocks selected by CMD+A
### 2.2—2.7 changelog
- `New` *Sanitize API* — [Sanitize Config](https://github.com/codex-team/codex.editor/blob/master/docs/tools.md#automatic-sanitize) of `Block Tools` now automatically extends by tags of `Inline Tools` that is enabled by current Tool by `inlineToolbar` option. You don't need more to specify `a, b, mark, code` manually. This feature will be added to fields that supports inline markup.

View file

@ -1,6 +1,6 @@
{
"name": "codex.editor",
"version": "2.7.22",
"version": "2.7.23",
"description": "CodeX Editor. Native JS, based on API and Open Source",
"main": "dist/codex-editor.js",
"types": "./types/index.d.ts",

View file

@ -168,6 +168,63 @@ export default class BlockEvents extends Module {
block.dropTarget = false;
}
/**
* Copying selected blocks
* Before putting to the clipboard we sanitize all blocks and then copy to the clipboard
*
* @param event
*/
public handleCommandC(event): void {
const { BlockSelection } = this.Editor;
if (!BlockSelection.anyBlockSelected) {
return;
}
/**
* Prevent default copy
* Remove "decline sound" on macOS
*/
event.preventDefault();
// Copy Selected Blocks
BlockSelection.copySelectedBlocks();
}
/**
* Copy and Delete selected Blocks
* @param event
*/
public handleCommandX(event): void {
const { BlockSelection, BlockManager, Caret } = this.Editor;
const currentBlock = BlockManager.currentBlock;
if (!currentBlock) {
return;
}
/**
* Prevent default copy
* Remove "decline sound" on macOS
*/
event.preventDefault();
/** Copy Blocks before removing */
if (currentBlock.selected || BlockManager.currentBlock.isEmpty) {
BlockSelection.copySelectedBlocks();
if (BlockSelection.allBlocksSelected) {
BlockManager.removeAllBlocks();
} else {
BlockManager.removeBlock();
Caret.setToBlock(BlockManager.insert(), CaretClass.positions.START);
}
/** Clear selection */
BlockSelection.clearSelection();
}
}
/**
* ENTER pressed on block
* @param {KeyboardEvent} event - keydown
@ -257,11 +314,29 @@ export default class BlockEvents extends Module {
*/
if (currentBlock.selected || BlockManager.currentBlock.isEmpty) {
if (BlockSelection.allBlocksSelected) {
this.removeAllBlocks();
BlockManager.removeAllBlocks();
} else {
this.removeCurrentBlock();
BlockManager.removeBlock();
/**
* 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 if (BlockManager.currentBlock.inputs.length === 0) {
/** If previous (now current) block doesn't contain inputs, remove it */
BlockManager.removeBlock();
BlockManager.insert();
}
Caret.setToBlock(BlockManager.currentBlock, CaretClass.positions.END);
}
/** Close Toolbar */
this.Editor.Toolbar.close();
/** Clear selection */
BlockSelection.clearSelection();
return;
@ -291,44 +366,6 @@ export default class BlockEvents extends Module {
}
}
/**
* 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 */
BlockManager.removeBlock();
/**
* 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 if (BlockManager.currentBlock.inputs.length === 0) {
/** If previous (now current) block doesn't contain inputs, remove it */
BlockManager.removeBlock();
BlockManager.insert();
}
Caret.setToBlock(BlockManager.currentBlock, CaretClass.positions.END);
this.Editor.Toolbar.close();
return true;
}
/**
* Merge current and previous Blocks if they have the same type
*/
@ -409,5 +446,4 @@ export default class BlockEvents extends Module {
return !(event.shiftKey || flippingToolboxItems || toolboxItemSelected);
}
}

View file

@ -120,6 +120,7 @@ export default class BlockManager extends Module {
*/
public async prepare() {
const blocks = new Blocks(this.Editor.UI.nodes.redactor);
const { BlockEvents, Shortcuts } = this.Editor;
/**
* We need to use Proxy to overload set/get [] operator.
@ -139,6 +140,22 @@ export default class BlockManager extends Module {
set: Blocks.set,
get: Blocks.get,
});
/** Copy shortcut */
Shortcuts.add({
name: 'CMD+C',
handler: (event) => {
BlockEvents.handleCommandC(event);
},
});
/** Copy and cut */
Shortcuts.add({
name: 'CMD+X',
handler: (event) => {
BlockEvents.handleCommandX(event);
},
});
}
/**

View file

@ -110,14 +110,6 @@ export default class BlockSelection extends Module {
},
});
/** Shortcut to copy selected blocks */
Shortcuts.add({
name: 'CMD+C',
handler: (event) => {
this.handleCommandC(event);
},
});
this.selection = new SelectionUtils();
}
@ -144,6 +136,28 @@ export default class BlockSelection extends Module {
this.allBlocksSelected = false;
}
/**
* Reduce each Block and copy its content
*/
public copySelectedBlocks(): void {
const { BlockManager, Sanitizer } = this.Editor;
const fakeClipboard = $.make('div');
BlockManager.blocks.filter( (block) => block.selected )
.forEach( (block) => {
/**
* Make <p> tag that holds clean HTML
*/
const cleanHTML = Sanitizer.clean(block.holder.innerHTML, this.sanitizerConfig);
const fragment = $.make('p');
fragment.innerHTML = cleanHTML;
fakeClipboard.appendChild(fragment);
});
_.copyTextToClipboard(fakeClipboard.innerHTML);
}
/**
* First CMD+A Selects current focused blocks,
* and consequent second CMD+A keypress selects all blocks
@ -169,49 +183,11 @@ export default class BlockSelection extends Module {
}
}
/**
* Copying selected blocks
* Before putting to the clipboard we sanitize all blocks and then copy to the clipboard
*
* @param event
*/
private handleCommandC(event): void {
const { BlockManager, Sanitizer } = this.Editor;
if (!this.anyBlockSelected) {
return;
}
/**
* Prevent default copy
* Remove "decline sound" on macOS
*/
event.preventDefault();
const fakeClipboard = $.make('div');
BlockManager.blocks.filter( (block) => block.selected )
.forEach( (block) => {
/**
* Make <p> tag that holds clean HTML
*/
const cleanHTML = Sanitizer.clean(block.holder.innerHTML, this.sanitizerConfig);
const fragment = $.make('p');
fragment.innerHTML = cleanHTML;
fakeClipboard.appendChild(fragment);
});
_.copyTextToClipboard(fakeClipboard.innerHTML);
}
/**
* Select All Blocks
* Each Block has selected setter that makes Block copyable
*/
private selectAllBlocks() {
const { BlockManager } = this.Editor;
this.allBlocksSelected = true;
}