mirror of
https://github.com/codex-team/editor.js
synced 2024-06-26 09:20:07 +02:00
New block lifecycle hook and BlockToolAPI: "moved" (#1007)
* Update CHANGELOG.md * feat: add swapped lifecycle hook * feat: deprecate swap and add move instead * feat: set fromIndex by default, add MoveEvent, add indices checks in blockManager * refactor: MoveEvent interface more event-like; docs: added docs for MoveEvent * fix asterix alignment due to tslint error * fix tslint * extending CustomEvent * update bundle * Update CHANGELOG.md Co-authored-by: Peter Savchenko <specc.dev@gmail.com> Co-authored-by: Murod Khaydarov <murod.haydarov@gmail.com>
This commit is contained in:
parent
3877380ee1
commit
8b838bf8aa
2
dist/editor.js
vendored
2
dist/editor.js
vendored
File diff suppressed because one or more lines are too long
|
@ -10,6 +10,8 @@
|
||||||
- `Fix` - Fix block-tune buttons alignment in some CSS-resetors that forces `box-sizing: border-box` rule [#1003](https://github.com/codex-team/editor.js/issues/1003)
|
- `Fix` - Fix block-tune buttons alignment in some CSS-resetors that forces `box-sizing: border-box` rule [#1003](https://github.com/codex-team/editor.js/issues/1003)
|
||||||
- `Improvements` - New style of a Block Settings button. Focused block background removed.
|
- `Improvements` - New style of a Block Settings button. Focused block background removed.
|
||||||
- `New` — Add in-house copy-paste support through `application/x-editor-js` mime-type
|
- `New` — Add in-house copy-paste support through `application/x-editor-js` mime-type
|
||||||
|
- `New` Block [lifecycle hook](tools.md#block-lifecycle-hooks) `moved`
|
||||||
|
- `Deprecated` — [`blocks.swap(fromIndex, toIndex)`](api.md) method is deprecated. Use `blocks.move(toIndex, fromIndex)` instead.
|
||||||
|
|
||||||
### 2.16.1
|
### 2.16.1
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,11 @@ Methods that working with Blocks
|
||||||
|
|
||||||
`renderFromHTML(data)` - parse and render passed HTML string (*not for production use*)
|
`renderFromHTML(data)` - parse and render passed HTML string (*not for production use*)
|
||||||
|
|
||||||
`swap(fromIndex, toIndex)` - swaps two Blocks by their positions
|
`swap(fromIndex, toIndex)` - swaps two Blocks by their positions (deprecated:
|
||||||
|
use 'move' instead)
|
||||||
|
|
||||||
|
`move(toIndex, fromIndex)` - moves block from one index to another position.
|
||||||
|
`fromIndex` will be the current block's index by default.
|
||||||
|
|
||||||
`delete(blockIndex?: Number)` - deletes Block with passed index
|
`delete(blockIndex?: Number)` - deletes Block with passed index
|
||||||
|
|
||||||
|
|
|
@ -476,3 +476,8 @@ Called each time Block contents is updated
|
||||||
### `removed()`
|
### `removed()`
|
||||||
|
|
||||||
Called after Block contents is removed from the page but before Block instance deleted
|
Called after Block contents is removed from the page but before Block instance deleted
|
||||||
|
|
||||||
|
### `moved(MoveEvent)`
|
||||||
|
|
||||||
|
Called after Block was moved. `MoveEvent` contains `fromIndex` and `toIndex`
|
||||||
|
respectively.
|
||||||
|
|
|
@ -92,7 +92,7 @@ export default class MoveDownTune implements BlockTune {
|
||||||
window.scrollTo(0, scrollOffset);
|
window.scrollTo(0, scrollOffset);
|
||||||
|
|
||||||
/** Change blocks positions */
|
/** Change blocks positions */
|
||||||
this.api.blocks.swap(currentBlockIndex, currentBlockIndex + 1);
|
this.api.blocks.move(currentBlockIndex + 1);
|
||||||
|
|
||||||
/** Hide the Tooltip */
|
/** Hide the Tooltip */
|
||||||
this.api.tooltip.hide();
|
this.api.tooltip.hide();
|
||||||
|
|
|
@ -46,7 +46,7 @@ export default class MoveUpTune implements BlockTune {
|
||||||
'click',
|
'click',
|
||||||
(event) => this.handleClick(event as MouseEvent, moveUpButton),
|
(event) => this.handleClick(event as MouseEvent, moveUpButton),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable tooltip module on button
|
* Enable tooltip module on button
|
||||||
|
@ -99,7 +99,7 @@ export default class MoveUpTune implements BlockTune {
|
||||||
window.scrollBy(0, -1 * scrollUpOffset);
|
window.scrollBy(0, -1 * scrollUpOffset);
|
||||||
|
|
||||||
/** Change blocks positions */
|
/** Change blocks positions */
|
||||||
this.api.blocks.swap(currentBlockIndex, currentBlockIndex - 1);
|
this.api.blocks.move(currentBlockIndex - 1);
|
||||||
|
|
||||||
/** Hide the Tooltip */
|
/** Hide the Tooltip */
|
||||||
this.api.tooltip.hide();
|
this.api.tooltip.hide();
|
||||||
|
|
|
@ -38,6 +38,7 @@ export enum BlockToolAPI {
|
||||||
*/
|
*/
|
||||||
APPEND_CALLBACK = 'appendCallback',
|
APPEND_CALLBACK = 'appendCallback',
|
||||||
RENDERED = 'rendered',
|
RENDERED = 'rendered',
|
||||||
|
MOVED = 'moved',
|
||||||
UPDATED = 'updated',
|
UPDATED = 'updated',
|
||||||
REMOVED = 'removed',
|
REMOVED = 'removed',
|
||||||
ON_PASTE = 'onPaste',
|
ON_PASTE = 'onPaste',
|
||||||
|
@ -441,7 +442,7 @@ export default class Block {
|
||||||
* @param {Object} data
|
* @param {Object} data
|
||||||
*/
|
*/
|
||||||
public async mergeWith(data: BlockToolData): Promise<void> {
|
public async mergeWith(data: BlockToolData): Promise<void> {
|
||||||
await this.tool.merge(data);
|
await this.tool.merge(data);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Extracts data from Block
|
* Extracts data from Block
|
||||||
|
@ -465,7 +466,7 @@ export default class Block {
|
||||||
return {
|
return {
|
||||||
tool: this.name,
|
tool: this.name,
|
||||||
data: finishedExtraction,
|
data: finishedExtraction,
|
||||||
time : measuringEnd - measuringStart,
|
time: measuringEnd - measuringStart,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -562,7 +563,7 @@ export default class Block {
|
||||||
private compose(): HTMLDivElement {
|
private compose(): HTMLDivElement {
|
||||||
const wrapper = $.make('div', Block.CSS.wrapper) as HTMLDivElement,
|
const wrapper = $.make('div', Block.CSS.wrapper) as HTMLDivElement,
|
||||||
contentNode = $.make('div', Block.CSS.content),
|
contentNode = $.make('div', Block.CSS.content),
|
||||||
pluginsContent = this.tool.render();
|
pluginsContent = this.tool.render();
|
||||||
|
|
||||||
contentNode.appendChild(pluginsContent);
|
contentNode.appendChild(pluginsContent);
|
||||||
wrapper.appendChild(contentNode);
|
wrapper.appendChild(contentNode);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as _ from './utils';
|
import * as _ from './utils';
|
||||||
import $ from './dom';
|
import $ from './dom';
|
||||||
import Block, {BlockToolAPI} from './block';
|
import Block, { BlockToolAPI } from './block';
|
||||||
|
import {MoveEvent, MoveEventDetail} from '../../types/tools';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Blocks
|
* @class Blocks
|
||||||
|
@ -127,6 +128,7 @@ export default class Blocks {
|
||||||
* Swaps blocks with indexes first and second
|
* Swaps blocks with indexes first and second
|
||||||
* @param {Number} first - first block index
|
* @param {Number} first - first block index
|
||||||
* @param {Number} second - second block index
|
* @param {Number} second - second block index
|
||||||
|
* @deprecated — use 'move' instead
|
||||||
*/
|
*/
|
||||||
public swap(first: number, second: number): void {
|
public swap(first: number, second: number): void {
|
||||||
const secondBlock = this.blocks[second];
|
const secondBlock = this.blocks[second];
|
||||||
|
@ -143,6 +145,42 @@ export default class Blocks {
|
||||||
this.blocks[first] = secondBlock;
|
this.blocks[first] = secondBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a block from one to another index
|
||||||
|
* @param {Number} toIndex - new index of the block
|
||||||
|
* @param {Number} fromIndex - block to move
|
||||||
|
*/
|
||||||
|
public move(toIndex: number, fromIndex: number): void {
|
||||||
|
/**
|
||||||
|
* cut out the block, move the DOM element and insert at the desired index
|
||||||
|
* again (the shifting within the blocks array will happen automatically).
|
||||||
|
* @see https://stackoverflow.com/a/44932690/1238150
|
||||||
|
*/
|
||||||
|
const block = this.blocks.splice(fromIndex, 1)[0];
|
||||||
|
|
||||||
|
// manipulate DOM
|
||||||
|
const prevIndex = toIndex - 1;
|
||||||
|
const previousBlockIndex = Math.max(0, prevIndex);
|
||||||
|
const previousBlock = this.blocks[previousBlockIndex];
|
||||||
|
|
||||||
|
if (toIndex > 0) {
|
||||||
|
this.insertToDOM(block, 'afterend', previousBlock);
|
||||||
|
} else {
|
||||||
|
this.insertToDOM(block, 'beforebegin', previousBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// move in array
|
||||||
|
this.blocks.splice(toIndex, 0, block);
|
||||||
|
|
||||||
|
// invoke hook
|
||||||
|
const event: MoveEvent = this.composeBlockEvent('move', {
|
||||||
|
fromIndex,
|
||||||
|
toIndex,
|
||||||
|
});
|
||||||
|
|
||||||
|
block.call(BlockToolAPI.MOVED, event);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert new Block at passed index
|
* Insert new Block at passed index
|
||||||
*
|
*
|
||||||
|
@ -261,4 +299,17 @@ export default class Blocks {
|
||||||
|
|
||||||
block.call(BlockToolAPI.RENDERED);
|
block.call(BlockToolAPI.RENDERED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composes Block event with passed type and details
|
||||||
|
*
|
||||||
|
* @param {String} type
|
||||||
|
* @param {MoveEventDetail} detail
|
||||||
|
*/
|
||||||
|
private composeBlockEvent(type: string, detail: MoveEventDetail): MoveEvent {
|
||||||
|
return new CustomEvent(type, {
|
||||||
|
detail,
|
||||||
|
},
|
||||||
|
) as MoveEvent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,7 @@ export default class Dom {
|
||||||
* Swap two elements in parent
|
* Swap two elements in parent
|
||||||
* @param {HTMLElement} el1 - from
|
* @param {HTMLElement} el1 - from
|
||||||
* @param {HTMLElement} el2 - to
|
* @param {HTMLElement} el2 - to
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public static swap(el1: HTMLElement, el2: HTMLElement): void {
|
public static swap(el1: HTMLElement, el2: HTMLElement): void {
|
||||||
// create marker element and insert it where el1 is
|
// create marker element and insert it where el1 is
|
||||||
|
|
|
@ -20,6 +20,7 @@ export default class BlocksAPI extends Module {
|
||||||
renderFromHTML: (data: string) => this.renderFromHTML(data),
|
renderFromHTML: (data: string) => this.renderFromHTML(data),
|
||||||
delete: () => this.delete(),
|
delete: () => this.delete(),
|
||||||
swap: (fromIndex: number, toIndex: number) => this.swap(fromIndex, toIndex),
|
swap: (fromIndex: number, toIndex: number) => this.swap(fromIndex, toIndex),
|
||||||
|
move: (toIndex: number, fromIndex?: number) => this.move(toIndex, fromIndex),
|
||||||
getBlockByIndex: (index: number) => this.getBlockByIndex(index),
|
getBlockByIndex: (index: number) => this.getBlockByIndex(index),
|
||||||
getCurrentBlockIndex: () => this.getCurrentBlockIndex(),
|
getCurrentBlockIndex: () => this.getCurrentBlockIndex(),
|
||||||
getBlocksCount: () => this.getBlocksCount(),
|
getBlocksCount: () => this.getBlocksCount(),
|
||||||
|
@ -60,6 +61,7 @@ export default class BlocksAPI extends Module {
|
||||||
* Call Block Manager method that swap Blocks
|
* Call Block Manager method that swap Blocks
|
||||||
* @param {number} fromIndex - position of first Block
|
* @param {number} fromIndex - position of first Block
|
||||||
* @param {number} toIndex - position of second Block
|
* @param {number} toIndex - position of second Block
|
||||||
|
* @deprecated — use 'move' instead
|
||||||
*/
|
*/
|
||||||
public swap(fromIndex: number, toIndex: number): void {
|
public swap(fromIndex: number, toIndex: number): void {
|
||||||
this.Editor.BlockManager.swap(fromIndex, toIndex);
|
this.Editor.BlockManager.swap(fromIndex, toIndex);
|
||||||
|
@ -71,6 +73,21 @@ export default class BlocksAPI extends Module {
|
||||||
this.Editor.Toolbar.move(false);
|
this.Editor.Toolbar.move(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move block from one index to another
|
||||||
|
* @param {Number} toIndex
|
||||||
|
* @param {number} fromIndex
|
||||||
|
*/
|
||||||
|
public move(toIndex: number, fromIndex?: number): void {
|
||||||
|
this.Editor.BlockManager.move(toIndex, fromIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move toolbar
|
||||||
|
* DO not close the settings
|
||||||
|
*/
|
||||||
|
this.Editor.Toolbar.move(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes Block
|
* Deletes Block
|
||||||
* @param blockIndex
|
* @param blockIndex
|
||||||
|
|
|
@ -552,6 +552,7 @@ export default class BlockManager extends Module {
|
||||||
* Swap Blocks Position
|
* Swap Blocks Position
|
||||||
* @param {Number} fromIndex
|
* @param {Number} fromIndex
|
||||||
* @param {Number} toIndex
|
* @param {Number} toIndex
|
||||||
|
* @deprecated — use 'move' instead
|
||||||
*/
|
*/
|
||||||
public swap(fromIndex, toIndex): void {
|
public swap(fromIndex, toIndex): void {
|
||||||
/** Move up current Block */
|
/** Move up current Block */
|
||||||
|
@ -561,6 +562,30 @@ export default class BlockManager extends Module {
|
||||||
this.currentBlockIndex = toIndex;
|
this.currentBlockIndex = toIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a block to a new index
|
||||||
|
* @param {Number} toIndex
|
||||||
|
* @param {Number} fromIndex
|
||||||
|
*/
|
||||||
|
public move(toIndex, fromIndex = this.currentBlockIndex): void {
|
||||||
|
// make sure indexes are valid and within a valid range
|
||||||
|
if (isNaN(toIndex) || isNaN(fromIndex)) {
|
||||||
|
_.log(`Warning during 'move' call: incorrect indices provided.`, 'warn');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.validateIndex(toIndex) || !this.validateIndex(fromIndex)) {
|
||||||
|
_.log(`Warning during 'move' call: indices cannot be lower than 0 or greater than the amount of blocks.`, 'warn');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Move up current Block */
|
||||||
|
this._blocks.move(toIndex, fromIndex);
|
||||||
|
|
||||||
|
/** Now actual block moved so that current block index changed */
|
||||||
|
this.currentBlockIndex = toIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets current Block Index -1 which means unknown
|
* Sets current Block Index -1 which means unknown
|
||||||
* and clear highlightings
|
* and clear highlightings
|
||||||
|
@ -604,4 +629,16 @@ export default class BlockManager extends Module {
|
||||||
Listeners.on(block.holder, 'dragover', (event) => BlockEvents.dragOver(event as DragEvent));
|
Listeners.on(block.holder, 'dragover', (event) => BlockEvents.dragOver(event as DragEvent));
|
||||||
Listeners.on(block.holder, 'dragleave', (event) => BlockEvents.dragLeave(event as DragEvent));
|
Listeners.on(block.holder, 'dragleave', (event) => BlockEvents.dragLeave(event as DragEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the given index is not lower than 0 or higher than the amount of blocks
|
||||||
|
* @param {number} index - index of blocks array to validate
|
||||||
|
*/
|
||||||
|
private validateIndex(index: number): boolean {
|
||||||
|
if (index < 0 || index >= this._blocks.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
8
types/api/blocks.d.ts
vendored
8
types/api/blocks.d.ts
vendored
|
@ -33,9 +33,17 @@ export interface Blocks {
|
||||||
* Swaps two Blocks
|
* Swaps two Blocks
|
||||||
* @param {number} fromIndex - block to swap
|
* @param {number} fromIndex - block to swap
|
||||||
* @param {number} toIndex - block to swap with
|
* @param {number} toIndex - block to swap with
|
||||||
|
* @deprecated — use 'move' instead
|
||||||
*/
|
*/
|
||||||
swap(fromIndex: number, toIndex: number): void;
|
swap(fromIndex: number, toIndex: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a block to a new index
|
||||||
|
* @param {number} toIndex - index where the block is moved to
|
||||||
|
* @param {number} fromIndex - block to move
|
||||||
|
*/
|
||||||
|
move(toIndex: number, fromIndex?: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns Block holder by Block index
|
* Returns Block holder by Block index
|
||||||
* @param {number} index
|
* @param {number} index
|
||||||
|
|
20
types/tools/block-tool.d.ts
vendored
20
types/tools/block-tool.d.ts
vendored
|
@ -1,9 +1,10 @@
|
||||||
import {ConversionConfig, PasteConfig, SanitizerConfig} from '../configs';
|
import { ConversionConfig, PasteConfig, SanitizerConfig } from '../configs';
|
||||||
import {BlockToolData} from './block-tool-data';
|
import { BlockToolData } from './block-tool-data';
|
||||||
import {BaseTool, BaseToolConstructable} from './tool';
|
import { BaseTool, BaseToolConstructable } from './tool';
|
||||||
import {ToolConfig} from './tool-config';
|
import { ToolConfig } from './tool-config';
|
||||||
import {API} from '../index';
|
import { API } from '../index';
|
||||||
import {PasteEvent} from './paste-events';
|
import { PasteEvent } from './paste-events';
|
||||||
|
import { MoveEvent } from './hook-events';
|
||||||
/**
|
/**
|
||||||
* Describe Block Tool object
|
* Describe Block Tool object
|
||||||
* @see {@link docs/tools.md}
|
* @see {@link docs/tools.md}
|
||||||
|
@ -65,6 +66,11 @@ export interface BlockTool extends BaseTool {
|
||||||
* Called after block removed from the page but before instance is deleted
|
* Called after block removed from the page but before instance is deleted
|
||||||
*/
|
*/
|
||||||
removed?(): void;
|
removed?(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after block was moved
|
||||||
|
*/
|
||||||
|
moved?(event: MoveEvent): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockToolConstructable extends BaseToolConstructable {
|
export interface BlockToolConstructable extends BaseToolConstructable {
|
||||||
|
@ -97,5 +103,5 @@ export interface BlockToolConstructable extends BaseToolConstructable {
|
||||||
* @constructor
|
* @constructor
|
||||||
* @return {BlockTool}
|
* @return {BlockTool}
|
||||||
*/
|
*/
|
||||||
new (config: {api: API, config: ToolConfig, data: BlockToolData}): BlockTool;
|
new(config: { api: API, config: ToolConfig, data: BlockToolData }): BlockTool;
|
||||||
}
|
}
|
||||||
|
|
23
types/tools/hook-events.d.ts
vendored
Normal file
23
types/tools/hook-events.d.ts
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* Event detail for block relocation
|
||||||
|
*/
|
||||||
|
export interface MoveEventDetail {
|
||||||
|
/**
|
||||||
|
* index the block was moved from
|
||||||
|
*/
|
||||||
|
fromIndex: number;
|
||||||
|
/**
|
||||||
|
* index the block was moved to
|
||||||
|
*/
|
||||||
|
toIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move event for block relocation
|
||||||
|
*/
|
||||||
|
export interface MoveEvent extends CustomEvent {
|
||||||
|
/**
|
||||||
|
* Override detail property of CustomEvent by MoveEvent hook
|
||||||
|
*/
|
||||||
|
readonly detail: MoveEventDetail;
|
||||||
|
}
|
1
types/tools/index.d.ts
vendored
1
types/tools/index.d.ts
vendored
|
@ -9,6 +9,7 @@ export * from './tool';
|
||||||
export * from './tool-config';
|
export * from './tool-config';
|
||||||
export * from './tool-settings';
|
export * from './tool-settings';
|
||||||
export * from './paste-events';
|
export * from './paste-events';
|
||||||
|
export * from './hook-events';
|
||||||
|
|
||||||
export type Tool = BaseTool | BlockTool | InlineTool;
|
export type Tool = BaseTool | BlockTool | InlineTool;
|
||||||
export type ToolConstructable = BaseToolConstructable | BlockToolConstructable | InlineToolConstructable;
|
export type ToolConstructable = BaseToolConstructable | BlockToolConstructable | InlineToolConstructable;
|
||||||
|
|
Loading…
Reference in a new issue