editor.js/src/components/modules/blockSelection.ts
horoyami beeeef0914
Mouse selection (#574)
* Mouse selection
2019-02-19 11:49:19 +03:00

244 lines
5.3 KiB
TypeScript

/**
* @class BlockSelection
* @classdesc Manages Block selection with shortcut CMD+A
*
* @module BlockSelection
* @version 1.0.0
*/
import Module from '../__module';
import _ from '../utils';
import $ from '../dom';
import SelectionUtils from '../selection';
import Block from '../block';
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 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);
}
/**
* Flag that identifies any Block selection
* @return {boolean}
*/
public get anyBlockSelected(): boolean {
const {BlockManager} = this.Editor;
return BlockManager.blocks.some((block) => block.selected === true);
}
/**
* 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;
/**
* Flag used to define native input selection
* In this case we allow double CMD+A to select Block
* @type {boolean}
*/
private nativeInputSelected: 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);
},
});
this.selection = new SelectionUtils();
}
/**
* Remove selection of Block
* @param {number?} index - Block index according to the BlockManager's indexes
*/
public unSelectBlockByIndex(index?) {
const {BlockManager} = this.Editor;
let block;
if (isNaN(index)) {
block = BlockManager.currentBlock;
} else {
block = BlockManager.getBlockByIndex(index);
}
block.selected = false;
}
/**
* Clear selection from Blocks
*/
public clearSelection(restoreSelection = false) {
this.needToSelectAll = false;
this.nativeInputSelected = false;
if (!this.anyBlockSelected || this.Editor.RectangleSelection.isRectActivated()) {
this.Editor.RectangleSelection.clearSelection();
return;
}
/**
* Restore selection when Block is already selected
* but someone tries to write something.
*/
if (restoreSelection) {
this.selection.restore();
}
/** Now all blocks cleared */
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);
}
/**
* select Block
* @param {number?} index - Block index according to the BlockManager's indexes
*/
public 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;
}
/**
* First CMD+A Selects current focused blocks,
* and consequent second CMD+A keypress selects all blocks
*
* @param {keydown} event
*/
private handleCommandA(event): void {
this.Editor.RectangleSelection.clearSelection();
/** allow default selection on native inputs */
if ($.isNativeInput(event.target) && !this.nativeInputSelected) {
this.nativeInputSelected = true;
return;
}
/** Prevent default selection */
event.preventDefault();
if (this.needToSelectAll) {
this.selectAllBlocks();
this.needToSelectAll = false;
} else {
this.selectBlockByIndex();
this.needToSelectAll = true;
}
}
/**
* Select All Blocks
* Each Block has selected setter that makes Block copyable
*/
private selectAllBlocks() {
this.allBlocksSelected = true;
}
}