editor.js/src/components/modules/blockSelection.ts
Murod Khaydarov 6a90784b69
Block selection (#483)
* initial commit for feature

* selection with cmd+a

* copy to clipboard

* use div instead of textarea

* select and copy improvements

* requested changes

* update

* improve styles

* remove missclick

* clear selection with escape and other keydowns except shift

* copy to clipboard with cmd+a&cmd+c

* restore selection after clearing block selection

* update submodules

* update

* rename func name

* rename getter selected

* small naming changes

* native selection fix

* fix with appendCallback

* add light animations to selection

* move appendcallback to the toolbox insertnew function

* upd styles

* update

* missed {}

* last fixes

* upgrade version
2018-11-13 19:11:47 +03:00

197 lines
4.2 KiB
TypeScript

/**
* @class BlockSelection
* @classdesc Manages Block selection with shortcut CMD+A and with mouse
*
* @module BlockSelection
* @version 1.0.0
*/
declare var Module: any;
declare var _: any;
declare var $: any;
import SelectionUtils from '../selection';
export default class BlockSelection extends Module {
/**
* Flag used to define block selection
* First CMD+A defines it as true and then second CMD+A selects all Blocks
* @type {boolean}
*/
private needToSelectAll: boolean = false;
/**
* SelectionUtils instance
* @type {SelectionUtils}
*/
private selection: SelectionUtils;
/**
* Module Preparation
* Registers Shortcuts CMD+A and CMD+C
* to select all and copy them
*/
public prepare(): void {
const { Shortcuts } = this.Editor;
/** Selection shortcut */
Shortcuts.add({
name: 'CMD+A',
handler: (event) => {
this.handleCommandA(event);
},
});
/** shortcut to copy all selected blocks */
Shortcuts.add({
name: 'CMD+C',
handler: (event) => {
this.handleCommandC(event);
},
});
this.selection = new SelectionUtils();
}
/**
* Clear selection from Blocks
*/
public clearSelection(restoreSelection = false) {
const { BlockManager } = this.Editor;
const anyBlockSelected = BlockManager.blocks.findIndex( (block) => block.selected === true) !== -1;
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.
*/
if (restoreSelection) {
this.selection.restore();
}
}
/**
* First CMD+A Selects current focused blocks,
* and consequent second CMD+A keypress selects all blocks
*
* @param {keydown} event
*/
private handleCommandA(event): void {
/** Prevent default selection */
event.preventDefault();
if (this.needToSelectAll) {
this.selectAllBlocks();
this.needToSelectAll = false;
} else {
this.selectBlockByIndex();
this.needToSelectAll = true;
}
}
/**
* 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;
const anyBlockSelected = BlockManager.blocks.some( (block) => block.selected === true);
if (!anyBlockSelected) {
return;
}
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;
BlockManager.blocks.forEach( (block) => block.selected = true);
}
/**
* select Block
* @param {number?} index - Block index according to the BlockManager's indexes
*/
private selectBlockByIndex(index?) {
const { BlockManager } = this.Editor;
/**
* Remove previous focused Block's state
*/
BlockManager.clearFocused();
let block;
if (isNaN(index)) {
block = BlockManager.currentBlock;
} else {
block = BlockManager.getBlockByIndex(index);
}
/** Save selection */
this.selection.save();
SelectionUtils.get()
.removeAllRanges();
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: {},
};
}
}