Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Refactoring] Tools #1595

Merged
merged 13 commits into from
Mar 31, 2021
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
[submodule "example/tools/simple-image"]
path = example/tools/simple-image
url = https://github.com/editor-js/simple-image
[submodule "src/components/tools/paragraph"]
path = src/components/tools/paragraph
[submodule "src/tools/paragraph"]
path = src/tools/paragraph
url = https://github.com/editor-js/paragraph
[submodule "example/tools/marker"]
path = example/tools/marker
Expand Down
87 changes: 47 additions & 40 deletions src/components/block/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
BlockAPI as BlockAPIInterface,
BlockTool,
BlockTool as IBlockTool,
BlockToolConstructable,
BlockToolData,
BlockTune,
Expand All @@ -16,12 +16,13 @@ import * as _ from '../utils';
import ApiModules from '../modules/api';
import BlockAPI from './api';
import { ToolType } from '../modules/tools';
import SelectionUtils from '../selection';
import BlockTool from '../tools/block';

/** Import default tunes */
import MoveUpTune from '../block-tunes/block-tune-move-up';
import DeleteTune from '../block-tunes/block-tune-delete';
import MoveDownTune from '../block-tunes/block-tune-move-down';
import SelectionUtils from '../selection';

/**
* Interface describes Block class constructor argument
Expand All @@ -38,14 +39,9 @@ interface BlockConstructorOptions {
data: BlockToolData;

/**
* Tool's class or constructor function
*/
Tool: BlockToolConstructable;

/**
* Tool settings from initial config
* Tool object
*/
settings: ToolSettings;
tool: BlockTool;

/**
* Editor's API methods
Expand Down Expand Up @@ -110,32 +106,27 @@ export default class Block {
/**
* Block Tool`s name
*/
public name: string;
public readonly name: string;

/**
* Instance of the Tool Block represents
*/
public tool: BlockTool;

/**
* Class blueprint of the ool Block represents
*/
public class: BlockToolConstructable;
public readonly tool: BlockTool;

/**
* User Tool configuration
*/
public settings: ToolConfig;
public readonly settings: ToolConfig;

/**
* Wrapper for Block`s content
*/
public holder: HTMLDivElement;
public readonly holder: HTMLDivElement;

/**
* Tunes used by Tool
*/
public tunes: BlockTune[];
public readonly tunes: BlockTune[];

/**
* Tool's user configuration
Expand All @@ -149,6 +140,11 @@ export default class Block {
*/
private cachedInputs: HTMLElement[] = [];

/**
* Tool class instance
*/
private readonly toolInstance: IBlockTool;

/**
* Editor`s API module
*/
Expand Down Expand Up @@ -209,27 +205,20 @@ export default class Block {
constructor({
name,
data,
Tool,
settings,
tool,
api,
readOnly,
}: BlockConstructorOptions) {
this.name = name;
this.class = Tool;
this.settings = settings;
this.config = settings.config || {};
this.settings = tool.settings;
this.config = tool.settings.config || {};
this.api = api;
this.blockAPI = new BlockAPI(this);

this.mutationObserver = new MutationObserver(this.didMutated);

this.tool = new Tool({
data,
config: this.config,
api: this.api.getMethodsForTool(name, ToolType.Block),
block: this.blockAPI,
readOnly,
});
this.tool = tool;
this.toolInstance = tool.instance(data, this.blockAPI, readOnly);

this.holder = this.compose();
/**
Expand Down Expand Up @@ -349,7 +338,7 @@ export default class Block {
* @returns {object}
*/
public get sanitize(): SanitizerConfig {
return this.tool.sanitize;
return this.tool.sanitizeConfig;
}

/**
Expand All @@ -359,7 +348,7 @@ export default class Block {
* @returns {boolean}
*/
public get mergeable(): boolean {
return _.isFunction(this.tool.merge);
return _.isFunction(this.toolInstance.merge);
}

/**
Expand Down Expand Up @@ -502,7 +491,7 @@ export default class Block {
/**
* call Tool's method with the instance context
*/
if (this.tool[methodName] && this.tool[methodName] instanceof Function) {
if (this.toolInstance[methodName] && this.toolInstance[methodName] instanceof Function) {
if (methodName === BlockToolAPI.APPEND_CALLBACK) {
_.log(
'`appendCallback` hook is deprecated and will be removed in the next major release. ' +
Expand All @@ -513,7 +502,7 @@ export default class Block {

try {
// eslint-disable-next-line no-useless-call
this.tool[methodName].call(this.tool, params);
this.toolInstance[methodName].call(this.toolInstance, params);
} catch (e) {
_.log(`Error during '${methodName}' call: ${e.message}`, 'error');
}
Expand All @@ -526,7 +515,7 @@ export default class Block {
* @param {BlockToolData} data - data to merge
*/
public async mergeWith(data: BlockToolData): Promise<void> {
await this.tool.merge(data);
await this.toolInstance.merge(data);
}

/**
Expand All @@ -536,7 +525,7 @@ export default class Block {
* @returns {object}
*/
public async save(): Promise<void|SavedData> {
const extractedBlock = await this.tool.save(this.pluginsContent as HTMLElement);
const extractedBlock = await this.toolInstance.save(this.pluginsContent as HTMLElement);

/**
* Measuring execution time
Expand Down Expand Up @@ -572,8 +561,8 @@ export default class Block {
public async validate(data: BlockToolData): Promise<boolean> {
let isValid = true;

if (this.tool.validate instanceof Function) {
isValid = await this.tool.validate(data);
if (this.toolInstance.validate instanceof Function) {
isValid = await this.toolInstance.validate(data);
}

return isValid;
Expand Down Expand Up @@ -672,6 +661,24 @@ export default class Block {
this.removeInputEvents();
}

/**
* Call Tool instance destroy method
*/
public destroy(): void {
if (_.isFunction(this.toolInstance.destroy)) {
this.toolInstance.destroy();
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* Call Tool instance renderSettings method
*/
public renderSettings(): HTMLElement | undefined {
if (_.isFunction(this.toolInstance.renderSettings)) {
return this.toolInstance.renderSettings();
}
}

/**
* Make default Block wrappers and put Tool`s content there
*
Expand All @@ -680,7 +687,7 @@ export default class Block {
private compose(): HTMLDivElement {
const wrapper = $.make('div', Block.CSS.wrapper) as HTMLDivElement,
contentNode = $.make('div', Block.CSS.content),
pluginsContent = this.tool.render();
pluginsContent = this.toolInstance.render();

contentNode.appendChild(pluginsContent);
wrapper.appendChild(contentNode);
Expand Down
13 changes: 6 additions & 7 deletions src/components/modules/blockEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export default class BlockEvents extends Module {
return;
}

const canOpenToolbox = Tools.isDefault(currentBlock.tool) && currentBlock.isEmpty;
const canOpenToolbox = currentBlock.tool.isDefault && currentBlock.isEmpty;
const conversionToolbarOpened = !currentBlock.isEmpty && ConversionToolbar.opened;
const inlineToolbarOpened = !currentBlock.isEmpty && !SelectionUtils.isCollapsed && InlineToolbar.opened;

Expand Down Expand Up @@ -206,15 +206,14 @@ export default class BlockEvents extends Module {
* @param {KeyboardEvent} event - keydown
*/
private enter(event: KeyboardEvent): void {
const { BlockManager, Tools, UI } = this.Editor;
const { BlockManager, UI } = this.Editor;
const currentBlock = BlockManager.currentBlock;
const tool = Tools.available[currentBlock.name];

/**
* Don't handle Enter keydowns when Tool sets enableLineBreaks to true.
* Uses for Tools like <code> where line breaks should be handled by default behaviour.
*/
if (tool && tool[Tools.INTERNAL_SETTINGS.IS_ENABLED_LINE_BREAKS]) {
if (currentBlock.tool.isLineBreaksEnabled) {
return;
}

Expand Down Expand Up @@ -253,7 +252,7 @@ export default class BlockEvents extends Module {
/**
* If new Block is empty
*/
if (this.Editor.Tools.isDefault(newCurrent.tool) && newCurrent.isEmpty) {
if (newCurrent.tool.isDefault && newCurrent.isEmpty) {
/**
* Show Toolbar
*/
Expand All @@ -276,7 +275,7 @@ export default class BlockEvents extends Module {
private backspace(event: KeyboardEvent): void {
const { BlockManager, BlockSelection, Caret } = this.Editor;
const currentBlock = BlockManager.currentBlock;
const tool = this.Editor.Tools.available[currentBlock.name];
const tool = currentBlock.tool;

/**
* Check if Block should be removed by current Backspace keydown
Expand Down Expand Up @@ -314,7 +313,7 @@ export default class BlockEvents extends Module {
*
* But if caret is at start of the block, we allow to remove it by backspaces
*/
if (tool && tool[this.Editor.Tools.INTERNAL_SETTINGS.IS_ENABLED_LINE_BREAKS] && !Caret.isAtStart) {
if (tool.isLineBreaksEnabled && !Caret.isAtStart) {
return;
}

Expand Down
15 changes: 6 additions & 9 deletions src/components/modules/blockManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import $ from '../dom';
import * as _ from '../utils';
import Blocks from '../blocks';
import { BlockToolConstructable, BlockToolData, PasteEvent } from '../../../types';
import BlockTool from '../tools/block';

/**
* @typedef {BlockManager} BlockManager
Expand Down Expand Up @@ -219,15 +220,13 @@ export default class BlockManager extends Module {
*
* @returns {Block}
*/
public composeBlock({ tool, data = {} }: {tool: string; data?: BlockToolData}): Block {
public composeBlock({ tool: name, data = {} }: {tool: string; data?: BlockToolData}): Block {
const readOnly = this.Editor.ReadOnly.isEnabled;
const settings = this.Editor.Tools.getToolSettings(tool);
const Tool = this.Editor.Tools.available[tool] as BlockToolConstructable;
const tool = this.Editor.Tools.blockTools.get(name);
const block = new Block({
name: tool,
name,
data,
Tool,
settings,
tool,
api: this.Editor.API,
readOnly,
});
Expand Down Expand Up @@ -703,9 +702,7 @@ export default class BlockManager extends Module {
*/
public async destroy(): Promise<void> {
await Promise.all(this.blocks.map((block) => {
if (_.isFunction(block.tool.destroy)) {
return block.tool.destroy();
}
return block.destroy();
}));
}

Expand Down
4 changes: 2 additions & 2 deletions src/components/modules/caret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export default class Caret extends Module {
* If last block is empty and it is an defaultBlock, set to that.
* Otherwise, append new empty block and set to that
*/
if (this.Editor.Tools.isDefault(lastBlock.tool) && lastBlock.isEmpty) {
if (lastBlock.tool.isDefault && lastBlock.isEmpty) {
this.setToBlock(lastBlock);
} else {
const newBlock = this.Editor.BlockManager.insertAtEnd();
Expand Down Expand Up @@ -409,7 +409,7 @@ export default class Caret extends Module {
* 2. If there is a last block and it is non-default --> and caret not at the end <--, do nothing
* (https://github.com/codex-team/editor.js/issues/1414)
*/
if (Tools.isDefault(currentBlock.tool) || !isAtEnd) {
if (currentBlock.tool.isDefault || !isAtEnd) {
return false;
}

Expand Down
Loading