[Refactor] ESLint fixed (#1100)

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
This commit is contained in:
George Berezhnoy 2020-04-18 21:55:19 +03:00 committed by GitHub
parent f5e9a6648e
commit 4c0d806a12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 1062 additions and 878 deletions

View file

@ -6,13 +6,40 @@
/** /**
* Temporary suppress some errors. We need to fix them partially in next patches * Temporary suppress some errors. We need to fix them partially in next patches
*/ */
"@typescript-eslint/explicit-function-return-type": ["warn"],
"@typescript-eslint/explicit-member-accessibility": ["warn"],
"@typescript-eslint/member-ordering": ["warn"],
"@typescript-eslint/no-empty-function": ["warn"],
"no-prototype-builtins": ["warn"],
"no-mixed-operators": ["warn"],
"import/no-duplicates": ["warn"], "import/no-duplicates": ["warn"],
"no-case-declarations": ["warn"] },
"settings": {
"jsdoc": {
"mode": "typescript"
}
},
"globals": {
"Node": true,
"Range": true,
"HTMLElement": true,
"HTMLDivElement": true,
"Element": true,
"Selection": true,
"SVGElement": true,
"Text": true,
"InsertPosition": true,
"PropertyKey": true,
"MouseEvent": true,
"TouchEvent": true,
"KeyboardEvent": true,
"ClipboardEvent": true,
"DragEvent": true,
"Event": true,
"EventTarget": true,
"Document": true,
"NodeList": true,
"File": true,
"FileList": true,
"MutationRecord": true,
"AddEventListenerOptions": true,
"DataTransfer": true,
"DOMRect": true,
"ClientRect": true,
"ArrayLike": true
} }
} }

2
dist/editor.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
/*! /*!
* Editor.js * Editor.js
* *
* @version 2.17.0 * @version 2.18.0
* *
* @licence Apache-2.0 * @licence Apache-2.0
* @author CodeX <https://codex.so> * @author CodeX <https://codex.so>
@ -15,8 +15,9 @@
* Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere
* At least, if there is no config overrides, that API uses Default configuration * At least, if there is no config overrides, that API uses Default configuration
* *
* @uses https://www.npmjs.com/package/html-janitor * @see {@link https://www.npmjs.com/package/html-janitor}
* @license https://github.com/guardian/html-janitor/blob/master/LICENSE * @license Apache-2.0
* @see {@link https://github.com/guardian/html-janitor/blob/master/LICENSE}
* *
* @param {SanitizerConfig} config - sanitizer extension * @param {SanitizerConfig} config - sanitizer extension
*/ */
@ -26,9 +27,9 @@
* *
* Short Description (눈_눈;) * Short Description (눈_눈;)
* *
* @version 2.0 * @version 2.18.0
* *
* @licence Apache-2.0 * @license Apache-2.0
* @author CodeX-Team <https://ifmo.su> * @author CodeX-Team <https://ifmo.su>
*/ */

View file

@ -2,7 +2,8 @@
### 2.18 ### 2.18
- `Improvements` - Deprecated TSLint replaced with ESLint, old config changed to [CodeX ESLint Config](https://github.com/codex-team/eslint-config). - `Improvements` - TSLint (deprecated) replaced with ESLint, old config changed to [CodeX ESLint Config](https://github.com/codex-team/eslint-config).
- `Improvements` - Fix many code-style issues, add missed annotations.
- `Improvements` - Adjusted GitHub action for ESLint. - `Improvements` - Adjusted GitHub action for ESLint.
### 2.17 ### 2.17

View file

@ -93,7 +93,8 @@ body {
max-width: 180px; max-width: 180px;
background: #4A9DF8; background: #4A9DF8;
padding: 17px 30px; padding: 17px 30px;
box-shadow: 0 6px 4px -4px rgba(137, 207, 255, 0.77); box-shadow: 0 22px 18px -4px rgba(137, 207, 255, 0.77);
transition: all 150ms ease;
cursor: pointer; cursor: pointer;
border-radius: 31px; border-radius: 31px;
color: #fff; color: #fff;
@ -103,6 +104,8 @@ body {
.ce-example__button:hover { .ce-example__button:hover {
background: #3D8DE5; background: #3D8DE5;
transform: translateY(2px);
box-shadow: 0 20px 15px -4px rgba(137, 207, 255, 0.77);
} }
.ce-example__output-footer { .ce-example__output-footer {

View file

@ -1,6 +1,6 @@
{ {
"name": "@editorjs/editorjs", "name": "@editorjs/editorjs",
"version": "2.17.0", "version": "2.18.0",
"description": "Editor.js — Native JS, based on API and Open Source", "description": "Editor.js — Native JS, based on API and Open Source",
"main": "dist/editor.js", "main": "dist/editor.js",
"types": "./types/index.d.ts", "types": "./types/index.d.ts",

View file

@ -17,9 +17,9 @@ declare const VERSION: string;
* *
* Short Description (_눈;) * Short Description (_눈;)
* *
* @version 2.0 * @version 2.18.0
* *
* @licence Apache-2.0 * @license Apache-2.0
* @author CodeX-Team <https://ifmo.su> * @author CodeX-Team <https://ifmo.su>
*/ */
export default class EditorJS { export default class EditorJS {
@ -35,7 +35,7 @@ export default class EditorJS {
public destroy: () => void; public destroy: () => void;
/** Editor version */ /** Editor version */
static get version(): string { public static get version(): string {
return VERSION; return VERSION;
} }
@ -46,7 +46,8 @@ export default class EditorJS {
/** /**
* Set default onReady function * Set default onReady function
*/ */
let onReady = () => {}; // eslint-disable-next-line @typescript-eslint/no-empty-function
let onReady = (): void => {};
/** /**
* If `onReady` was passed in `configuration` then redefine onReady function * If `onReady` was passed in `configuration` then redefine onReady function
@ -75,18 +76,18 @@ export default class EditorJS {
/** /**
* Export external API methods * Export external API methods
* *
* @param editor * @param {Core} editor Editor's instance
*/ */
public exportAPI(editor: Core): void { public exportAPI(editor: Core): void {
const fieldsToExport = [ 'configuration' ]; const fieldsToExport = [ 'configuration' ];
const destroy = () => { const destroy = (): void => {
editor.moduleInstances.Listeners.removeAll(); editor.moduleInstances.Listeners.removeAll();
editor.moduleInstances.UI.destroy(); editor.moduleInstances.UI.destroy();
editor.moduleInstances.ModificationsObserver.destroy(); editor.moduleInstances.ModificationsObserver.destroy();
editor = null; editor = null;
for (const field in this) { for (const field in this) {
if (this.hasOwnProperty(field)) { if (Object.prototype.hasOwnProperty.call(this, field)) {
delete this[field]; delete this[field];
} }
} }

View file

@ -28,7 +28,7 @@ export default class Module {
/** /**
* @class * @class
* @param {EditorConfig} * @param {EditorConfig} config - Editor's config
*/ */
constructor({ config }: ModuleConfig) { constructor({ config }: ModuleConfig) {
if (new.target === Module) { if (new.target === Module) {
@ -41,9 +41,9 @@ export default class Module {
/** /**
* Editor modules setter * Editor modules setter
* *
* @param {EditorModules} Editor * @param {EditorModules} Editor - Editor's Modules
*/ */
set state(Editor: EditorModules) { public set state(Editor: EditorModules) {
this.Editor = Editor; this.Editor = Editor;
} }
} }

View file

@ -14,7 +14,7 @@ export default class DeleteTune implements BlockTune {
/** /**
* Property that contains Editor.js API methods * Property that contains Editor.js API methods
* *
* @see {docs/api.md} * @see {@link docs/api.md}
*/ */
private readonly api: API; private readonly api: API;
@ -35,7 +35,7 @@ export default class DeleteTune implements BlockTune {
/** /**
* set false confirmation state * set false confirmation state
*/ */
private resetConfirmation: () => void; private readonly resetConfirmation: () => void;
/** /**
* Tune nodes * Tune nodes
@ -47,12 +47,12 @@ export default class DeleteTune implements BlockTune {
/** /**
* DeleteTune constructor * DeleteTune constructor
* *
* @param {{api: API}} api * @param {API} api - Editor's API
*/ */
constructor({ api }) { constructor({ api }) {
this.api = api; this.api = api;
this.resetConfirmation = () => { this.resetConfirmation = (): void => {
this.setConfirmation(false); this.setConfirmation(false);
}; };
} }
@ -60,9 +60,9 @@ export default class DeleteTune implements BlockTune {
/** /**
* Create "Delete" button and add click event listener * Create "Delete" button and add click event listener
* *
* @returns [Element} * @returns {HTMLElement}
*/ */
public render() { public render(): HTMLElement {
this.nodes.button = $.make('div', [this.CSS.button, this.CSS.buttonDelete], {}); this.nodes.button = $.make('div', [this.CSS.button, this.CSS.buttonDelete], {});
this.nodes.button.appendChild($.svg('cross', 12, 12)); this.nodes.button.appendChild($.svg('cross', 12, 12));
this.api.listeners.on(this.nodes.button, 'click', (event: MouseEvent) => this.handleClick(event), false); this.api.listeners.on(this.nodes.button, 'click', (event: MouseEvent) => this.handleClick(event), false);
@ -78,7 +78,7 @@ export default class DeleteTune implements BlockTune {
/** /**
* Delete block conditions passed * Delete block conditions passed
* *
* @param {MouseEvent} event * @param {MouseEvent} event - click event
*/ */
public handleClick(event: MouseEvent): void { public handleClick(event: MouseEvent): void {
/** /**
@ -114,9 +114,9 @@ export default class DeleteTune implements BlockTune {
/** /**
* change tune state * change tune state
* *
* @param state * @param {boolean} state - delete confirmation state
*/ */
private setConfirmation(state): void { private setConfirmation(state: boolean): void {
this.needConfirmation = state; this.needConfirmation = state;
this.nodes.button.classList.add(this.CSS.buttonConfirm); this.nodes.button.classList.add(this.CSS.buttonConfirm);
} }

View file

@ -15,7 +15,7 @@ export default class MoveDownTune implements BlockTune {
/** /**
* Property that contains Editor.js API methods * Property that contains Editor.js API methods
* *
* @see {api.md} * @see {@link docs/api.md}
*/ */
private readonly api: API; private readonly api: API;
@ -33,7 +33,7 @@ export default class MoveDownTune implements BlockTune {
/** /**
* MoveDownTune constructor * MoveDownTune constructor
* *
* @param {{api: API}} api * @param {API} api Editor's API
*/ */
constructor({ api }) { constructor({ api }) {
this.api = api; this.api = api;
@ -41,8 +41,10 @@ export default class MoveDownTune implements BlockTune {
/** /**
* Return 'move down' button * Return 'move down' button
*
* @returns {HTMLElement}
*/ */
public render() { public render(): HTMLElement {
const moveDownButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {}); const moveDownButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
moveDownButton.appendChild($.svg('arrow-down', 14, 14)); moveDownButton.appendChild($.svg('arrow-down', 14, 14));
@ -64,10 +66,10 @@ export default class MoveDownTune implements BlockTune {
/** /**
* Handle clicks on 'move down' button * Handle clicks on 'move down' button
* *
* @param {MouseEvent} event * @param {MouseEvent} event - click event
* @param {HTMLElement} button * @param {HTMLElement} button - clicked button
*/ */
public handleClick(event: MouseEvent, button: HTMLElement) { public handleClick(event: MouseEvent, button: HTMLElement): void {
const currentBlockIndex = this.api.blocks.getCurrentBlockIndex(); const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();
// If Block is last do nothing // If Block is last do nothing

View file

@ -14,7 +14,7 @@ export default class MoveUpTune implements BlockTune {
/** /**
* Property that contains Editor.js API methods * Property that contains Editor.js API methods
* *
* @see {api.md} * @see {@link docs/api.md}
*/ */
private readonly api: API; private readonly api: API;
@ -32,7 +32,7 @@ export default class MoveUpTune implements BlockTune {
/** /**
* MoveUpTune constructor * MoveUpTune constructor
* *
* @param {{api: API}} api * @param {API} api - Editor's API
*/ */
constructor({ api }) { constructor({ api }) {
this.api = api; this.api = api;
@ -41,7 +41,7 @@ export default class MoveUpTune implements BlockTune {
/** /**
* Create "MoveUp" button and add click event listener * Create "MoveUp" button and add click event listener
* *
* @returns [HTMLElement} * @returns {HTMLElement}
*/ */
public render(): HTMLElement { public render(): HTMLElement {
const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {}); const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});
@ -65,8 +65,8 @@ export default class MoveUpTune implements BlockTune {
/** /**
* Move current block up * Move current block up
* *
* @param {MouseEvent} event * @param {MouseEvent} event - click event
* @param {HTMLElement} button * @param {HTMLElement} button - clicked button
*/ */
public handleClick(event: MouseEvent, button: HTMLElement): void { public handleClick(event: MouseEvent, button: HTMLElement): void {
const currentBlockIndex = this.api.blocks.getCurrentBlockIndex(); const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();

View file

@ -47,10 +47,9 @@ export enum BlockToolAPI {
/** /**
* @classdesc Abstract Block class that contains Block information, Tool name and Tool class instance * @classdesc Abstract Block class that contains Block information, Tool name and Tool class instance
* *
* @property tool - Tool instance * @property {BlockTool} tool - Tool instance
* @property html - Returns HTML content of plugin * @property {HTMLElement} holder - Div element that wraps block content with Tool's content. Has `ce-block` CSS class
* @property holder - Div element that wraps block content with Tool's content. Has `ce-block` CSS class * @property {HTMLElement} pluginsContent - HTML content that returns by Tool's render function
* @property pluginsContent - HTML content that returns by Tool's render function
*/ */
export default class Block { export default class Block {
/** /**
@ -58,7 +57,7 @@ export default class Block {
* *
* @returns {{wrapper: string, content: string}} * @returns {{wrapper: string, content: string}}
*/ */
static get CSS() { public static get CSS(): {[name: string]: string} {
return { return {
wrapper: 'ce-block', wrapper: 'ce-block',
wrapperStretched: 'ce-block--stretched', wrapperStretched: 'ce-block--stretched',
@ -69,259 +68,6 @@ export default class Block {
}; };
} }
/**
* Find and return all editable elements (contenteditables and native inputs) in the Tool HTML
*
* @returns {HTMLElement[]}
*/
get inputs(): HTMLElement[] {
/**
* Return from cache if existed
*/
if (this.cachedInputs.length !== 0) {
return this.cachedInputs;
}
const content = this.holder;
const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url'];
const selector = '[contenteditable], textarea, input:not([type]), ' +
allowedInputTypes.map((type) => `input[type="${type}"]`).join(', ');
let inputs = _.array(content.querySelectorAll(selector));
/**
* If contenteditable element contains block elements, treat them as inputs.
*/
inputs = inputs.reduce((result, input) => {
if ($.isNativeInput(input) || $.containsOnlyInlineElements(input)) {
return [...result, input];
}
return [...result, ...$.getDeepestBlockElements(input)];
}, []);
/**
* If inputs amount was changed we need to check if input index is bigger then inputs array length
*/
if (this.inputIndex > inputs.length - 1) {
this.inputIndex = inputs.length - 1;
}
/**
* Cache inputs
*/
this.cachedInputs = inputs;
return inputs;
}
/**
* Return current Tool`s input
*
* @returns {HTMLElement}
*/
get currentInput(): HTMLElement | Node {
return this.inputs[this.inputIndex];
}
/**
* Set input index to the passed element
*
* @param {HTMLElement} element
*/
set currentInput(element: HTMLElement | Node) {
const index = this.inputs.findIndex((input) => input === element || input.contains(element));
if (index !== -1) {
this.inputIndex = index;
}
}
/**
* Return first Tool`s input
*
* @returns {HTMLElement}
*/
get firstInput(): HTMLElement {
return this.inputs[0];
}
/**
* Return first Tool`s input
*
* @returns {HTMLElement}
*/
get lastInput(): HTMLElement {
const inputs = this.inputs;
return inputs[inputs.length - 1];
}
/**
* Return next Tool`s input or undefined if it doesn't exist
*
* @returns {HTMLElement}
*/
get nextInput(): HTMLElement {
return this.inputs[this.inputIndex + 1];
}
/**
* Return previous Tool`s input or undefined if it doesn't exist
*
* @returns {HTMLElement}
*/
get previousInput(): HTMLElement {
return this.inputs[this.inputIndex - 1];
}
/**
* Returns Plugins content
*
* @returns {HTMLElement}
*/
get pluginsContent(): HTMLElement {
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
if (blockContentNodes && blockContentNodes.childNodes.length) {
/**
* Editors Block content can contain different Nodes from extensions
* We use DOM isExtensionNode to ignore such Nodes and return first Block that does not match filtering list
*/
for (let child = blockContentNodes.childNodes.length - 1; child >= 0; child--) {
const contentNode = blockContentNodes.childNodes[child];
if (!$.isExtensionNode(contentNode)) {
return contentNode as HTMLElement;
}
}
}
return null;
}
/**
* Get Block's JSON data
*
* @returns {object}
*/
get data(): BlockToolData {
return this.save().then((savedObject) => {
if (savedObject && !_.isEmpty(savedObject.data)) {
return savedObject.data;
} else {
return {};
}
});
}
/**
* Returns tool's sanitizer config
*
* @returns {object}
*/
get sanitize(): SanitizerConfig {
return this.tool.sanitize;
}
/**
* is block mergeable
* We plugin have merge function then we call it mergable
*
* @returns {boolean}
*/
get mergeable(): boolean {
return typeof this.tool.merge === 'function';
}
/**
* Check block for emptiness
*
* @returns {boolean}
*/
get isEmpty(): boolean {
const emptyText = $.isEmpty(this.pluginsContent);
const emptyMedia = !this.hasMedia;
return emptyText && emptyMedia;
}
/**
* Check if block has a media content such as images, iframes and other
*
* @returns {boolean}
*/
get hasMedia(): boolean {
/**
* This tags represents media-content
*
* @type {string[]}
*/
const mediaTags = [
'img',
'iframe',
'video',
'audio',
'source',
'input',
'textarea',
'twitterwidget',
];
return !!this.holder.querySelector(mediaTags.join(','));
}
/**
* Set focused state
*
* @param {boolean} state - 'true' to select, 'false' to remove selection
*/
set focused(state: boolean) {
this.holder.classList.toggle(Block.CSS.focused, state);
}
/**
* Set selected state
* We don't need to mark Block as Selected when it is empty
*
* @param {boolean} state - 'true' to select, 'false' to remove selection
*/
set selected(state: boolean) {
if (state) {
this.holder.classList.add(Block.CSS.selected);
} else {
this.holder.classList.remove(Block.CSS.selected);
}
}
/**
* Returns True if it is Selected
*
* @returns {boolean}
*/
get selected(): boolean {
return this.holder.classList.contains(Block.CSS.selected);
}
/**
* Set stretched state
*
* @param {boolean} state - 'true' to enable, 'false' to disable stretched statte
*/
set stretched(state: boolean) {
this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
}
/**
* Toggle drop target state
*
* @param {boolean} state
*/
public set dropTarget(state) {
this.holder.classList.toggle(Block.CSS.dropTarget, state);
}
/** /**
* Block Tool`s name * Block Tool`s name
*/ */
@ -432,15 +178,268 @@ export default class Block {
this.tunes = this.makeTunes(); this.tunes = this.makeTunes();
} }
/**
* Find and return all editable elements (contenteditables and native inputs) in the Tool HTML
*
* @returns {HTMLElement[]}
*/
public get inputs(): HTMLElement[] {
/**
* Return from cache if existed
*/
if (this.cachedInputs.length !== 0) {
return this.cachedInputs;
}
const content = this.holder;
const allowedInputTypes = ['text', 'password', 'email', 'number', 'search', 'tel', 'url'];
const selector = '[contenteditable], textarea, input:not([type]), ' +
allowedInputTypes.map((type) => `input[type="${type}"]`).join(', ');
let inputs = _.array(content.querySelectorAll(selector));
/**
* If contenteditable element contains block elements, treat them as inputs.
*/
inputs = inputs.reduce((result, input) => {
if ($.isNativeInput(input) || $.containsOnlyInlineElements(input)) {
return [...result, input];
}
return [...result, ...$.getDeepestBlockElements(input)];
}, []);
/**
* If inputs amount was changed we need to check if input index is bigger then inputs array length
*/
if (this.inputIndex > inputs.length - 1) {
this.inputIndex = inputs.length - 1;
}
/**
* Cache inputs
*/
this.cachedInputs = inputs;
return inputs;
}
/**
* Return current Tool`s input
*
* @returns {HTMLElement}
*/
public get currentInput(): HTMLElement | Node {
return this.inputs[this.inputIndex];
}
/**
* Set input index to the passed element
*
* @param {HTMLElement | Node} element - HTML Element to set as current input
*/
public set currentInput(element: HTMLElement | Node) {
const index = this.inputs.findIndex((input) => input === element || input.contains(element));
if (index !== -1) {
this.inputIndex = index;
}
}
/**
* Return first Tool`s input
*
* @returns {HTMLElement}
*/
public get firstInput(): HTMLElement {
return this.inputs[0];
}
/**
* Return first Tool`s input
*
* @returns {HTMLElement}
*/
public get lastInput(): HTMLElement {
const inputs = this.inputs;
return inputs[inputs.length - 1];
}
/**
* Return next Tool`s input or undefined if it doesn't exist
*
* @returns {HTMLElement}
*/
public get nextInput(): HTMLElement {
return this.inputs[this.inputIndex + 1];
}
/**
* Return previous Tool`s input or undefined if it doesn't exist
*
* @returns {HTMLElement}
*/
public get previousInput(): HTMLElement {
return this.inputs[this.inputIndex - 1];
}
/**
* Returns Plugins content
*
* @returns {HTMLElement}
*/
public get pluginsContent(): HTMLElement {
const blockContentNodes = this.holder.querySelector(`.${Block.CSS.content}`);
if (blockContentNodes && blockContentNodes.childNodes.length) {
/**
* Editors Block content can contain different Nodes from extensions
* We use DOM isExtensionNode to ignore such Nodes and return first Block that does not match filtering list
*/
for (let child = blockContentNodes.childNodes.length - 1; child >= 0; child--) {
const contentNode = blockContentNodes.childNodes[child];
if (!$.isExtensionNode(contentNode)) {
return contentNode as HTMLElement;
}
}
}
return null;
}
/**
* Get Block's JSON data
*
* @returns {object}
*/
public get data(): BlockToolData {
return this.save().then((savedObject) => {
if (savedObject && !_.isEmpty(savedObject.data)) {
return savedObject.data;
} else {
return {};
}
});
}
/**
* Returns tool's sanitizer config
*
* @returns {object}
*/
public get sanitize(): SanitizerConfig {
return this.tool.sanitize;
}
/**
* is block mergeable
* We plugin have merge function then we call it mergable
*
* @returns {boolean}
*/
public mergeable(): boolean {
return typeof this.tool.merge === 'function';
}
/**
* Check block for emptiness
*
* @returns {boolean}
*/
public get isEmpty(): boolean {
const emptyText = $.isEmpty(this.pluginsContent);
const emptyMedia = !this.hasMedia;
return emptyText && emptyMedia;
}
/**
* Check if block has a media content such as images, iframes and other
*
* @returns {boolean}
*/
public get hasMedia(): boolean {
/**
* This tags represents media-content
*
* @type {string[]}
*/
const mediaTags = [
'img',
'iframe',
'video',
'audio',
'source',
'input',
'textarea',
'twitterwidget',
];
return !!this.holder.querySelector(mediaTags.join(','));
}
/**
* Set focused state
*
* @param {boolean} state - 'true' to select, 'false' to remove selection
*/
public set focused(state: boolean) {
this.holder.classList.toggle(Block.CSS.focused, state);
}
/**
* Set selected state
* We don't need to mark Block as Selected when it is empty
*
* @param {boolean} state - 'true' to select, 'false' to remove selection
*/
public set selected(state: boolean) {
if (state) {
this.holder.classList.add(Block.CSS.selected);
} else {
this.holder.classList.remove(Block.CSS.selected);
}
}
/**
* Returns True if it is Selected
*
* @returns {boolean}
*/
public get selected(): boolean {
return this.holder.classList.contains(Block.CSS.selected);
}
/**
* Set stretched state
*
* @param {boolean} state - 'true' to enable, 'false' to disable stretched statte
*/
public set stretched(state: boolean) {
this.holder.classList.toggle(Block.CSS.wrapperStretched, state);
}
/**
* Toggle drop target state
*
* @param {boolean} state - 'true' if block is drop target, false otherwise
*/
public set dropTarget(state) {
this.holder.classList.toggle(Block.CSS.dropTarget, state);
}
/** /**
* Calls Tool's method * Calls Tool's method
* *
* Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function * Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function
* *
* @param {string} methodName * @param {string} methodName - method to call
* @param {object} params * @param {object} params - method argument
*/ */
public call(methodName: string, params?: object) { public call(methodName: string, params?: object): void {
/** /**
* call Tool's method with the instance context * call Tool's method with the instance context
*/ */
@ -457,7 +456,7 @@ export default class Block {
/** /**
* Call plugins merge method * Call plugins merge method
* *
* @param {object} data * @param {BlockToolData} data - data to merge
*/ */
public async mergeWith(data: BlockToolData): Promise<void> { public async mergeWith(data: BlockToolData): Promise<void> {
await this.tool.merge(data); await this.tool.merge(data);
@ -500,7 +499,7 @@ export default class Block {
* *
* @description Method returns true|false whether data passed the validation or not * @description Method returns true|false whether data passed the validation or not
* *
* @param {BlockToolData} data * @param {BlockToolData} data - data to validate
* @returns {Promise<boolean>} valid * @returns {Promise<boolean>} valid
*/ */
public async validate(data: BlockToolData): Promise<boolean> { public async validate(data: BlockToolData): Promise<boolean> {
@ -574,7 +573,7 @@ export default class Block {
/** /**
* Is fired when Block will be unselected * Is fired when Block will be unselected
*/ */
public willUnselect() { public willUnselect(): void {
this.mutationObserver.disconnect(); this.mutationObserver.disconnect();
} }

View file

@ -1,7 +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'; import { MoveEvent } from '../../types/tools';
/** /**
* @class Blocks * @class Blocks
@ -13,6 +13,26 @@ import { MoveEvent, MoveEventDetail } from '../../types/tools';
* *
*/ */
export default class Blocks { export default class Blocks {
/**
* Array of Block instances in order of addition
*/
public blocks: Block[];
/**
* Editor`s area where to add Block`s HTML
*/
public workingArea: HTMLElement;
/**
* @class
*
* @param {HTMLElement} workingArea editor`s working node
*/
constructor(workingArea: HTMLElement) {
this.blocks = [];
this.workingArea = workingArea;
}
/** /**
* Get length of Block instances array * Get length of Block instances array
* *
@ -47,11 +67,11 @@ export default class Blocks {
* blocks[0] = new Block(...) * blocks[0] = new Block(...)
* *
* @param {Blocks} instance Blocks instance * @param {Blocks} instance Blocks instance
* @param {number|string} property block index or any Blocks class property to set * @param {PropertyKey} property block index or any Blocks class property key to set
* @param {Block} value value to set * @param {Block} value value to set
* @returns {boolean} * @returns {boolean}
*/ */
public static set(instance: Blocks, property: number | string, value: Block | any) { public static set(instance: Blocks, property: PropertyKey, value: Block | unknown): boolean {
/** /**
* If property name is not a number (method or other property, access it via reflect * If property name is not a number (method or other property, access it via reflect
*/ */
@ -67,7 +87,7 @@ export default class Blocks {
* @example * @example
* blocks[0] = new Block(); * blocks[0] = new Block();
*/ */
instance.insert(+property, value); instance.insert(+(property as number), value as Block);
return true; return true;
} }
@ -76,10 +96,10 @@ export default class Blocks {
* Proxy trap to implement array-like getter * Proxy trap to implement array-like getter
* *
* @param {Blocks} instance Blocks instance * @param {Blocks} instance Blocks instance
* @param {number|string} property Blocks class property * @param {PropertyKey} property Blocks class property key
* @returns {Block|*} * @returns {Block|*}
*/ */
public static get(instance: Blocks, property: any | number) { public static get(instance: Blocks, property: PropertyKey): Block | unknown {
/** /**
* If property is not a number, get it via Reflect object * If property is not a number, get it via Reflect object
*/ */
@ -90,33 +110,13 @@ export default class Blocks {
/** /**
* If property is a number (Block index) return Block by passed index * If property is a number (Block index) return Block by passed index
*/ */
return instance.get(+property); return instance.get(+(property as number));
}
/**
* Array of Block instances in order of addition
*/
public blocks: Block[];
/**
* Editor`s area where to add Block`s HTML
*/
public workingArea: HTMLElement;
/**
* @class
*
* @param {HTMLElement} workingArea editor`s working node
*/
constructor(workingArea: HTMLElement) {
this.blocks = [];
this.workingArea = workingArea;
} }
/** /**
* Push new Block to the blocks array and append it to working area * Push new Block to the blocks array and append it to working area
* *
* @param {Block} block * @param {Block} block - Block to add
*/ */
public push(block: Block): void { public push(block: Block): void {
this.blocks.push(block); this.blocks.push(block);
@ -228,7 +228,7 @@ export default class Blocks {
/** /**
* Remove block * Remove block
* *
* @param {number|null} index * @param {number} index - index of Block to remove
*/ */
public remove(index: number): void { public remove(index: number): void {
if (isNaN(index)) { if (isNaN(index)) {
@ -258,7 +258,7 @@ export default class Blocks {
* *
* @todo decide if this method is necessary * @todo decide if this method is necessary
* *
* @param {Block} targetBlock target after wich Block should be inserted * @param {Block} targetBlock target after which Block should be inserted
* @param {Block} newBlock Block to insert * @param {Block} newBlock Block to insert
*/ */
public insertAfter(targetBlock: Block, newBlock: Block): void { public insertAfter(targetBlock: Block, newBlock: Block): void {
@ -280,7 +280,7 @@ export default class Blocks {
/** /**
* Return index of passed Block * Return index of passed Block
* *
* @param {Block} block * @param {Block} block - Block to find
* @returns {number} * @returns {number}
*/ */
public indexOf(block: Block): number { public indexOf(block: Block): number {
@ -307,13 +307,12 @@ export default class Blocks {
/** /**
* Composes Block event with passed type and details * Composes Block event with passed type and details
* *
* @param {string} type * @param {string} type - event type
* @param {MoveEventDetail} detail * @param {object} detail - event detail
*/ */
private composeBlockEvent(type: string, detail: MoveEventDetail): MoveEvent { private composeBlockEvent(type: string, detail: object): MoveEvent {
return new CustomEvent(type, { return new CustomEvent(type, {
detail, detail,
} }) as MoveEvent;
) as MoveEvent;
} }
} }

View file

@ -1,8 +1,10 @@
import $ from './dom'; import $ from './dom';
// eslint-disable-next-line import/no-duplicates
import * as _ from './utils'; import * as _ from './utils';
// eslint-disable-next-line import/no-duplicates
import { LogLevels } from './utils';
import { EditorConfig, OutputData, SanitizerConfig } from '../../types'; import { EditorConfig, OutputData, SanitizerConfig } from '../../types';
import { EditorModules } from '../types-internal/editor-modules'; import { EditorModules } from '../types-internal/editor-modules';
import { LogLevels } from './utils';
/** /**
* @typedef {Core} Core - editor core class * @typedef {Core} Core - editor core class
@ -31,8 +33,8 @@ contextRequire.keys().forEach((filename) => {
* *
* @classdesc Editor.js core class * @classdesc Editor.js core class
* *
* @property this.config - all settings * @property {EditorConfig} config - all settings
* @property this.moduleInstances - constructed editor components * @property {EditorModules} moduleInstances - constructed editor components
* *
* @type {Core} * @type {Core}
*/ */
@ -110,9 +112,9 @@ export default class Core {
/** /**
* Setting for configuration * Setting for configuration
* *
* @param {EditorConfig|string|undefined} config * @param {EditorConfig|string} config - Editor's config to set
*/ */
set configuration(config: EditorConfig|string) { public set configuration(config: EditorConfig|string) {
/** /**
* Process zero-configuration or with only holderId * Process zero-configuration or with only holderId
* Make config object * Make config object
@ -185,8 +187,10 @@ export default class Core {
this.config.hideToolbar = this.config.hideToolbar ? this.config.hideToolbar : false; this.config.hideToolbar = this.config.hideToolbar ? this.config.hideToolbar : false;
this.config.tools = this.config.tools || {}; this.config.tools = this.config.tools || {};
this.config.data = this.config.data || {} as OutputData; this.config.data = this.config.data || {} as OutputData;
this.config.onReady = this.config.onReady || (() => {}); // eslint-disable-next-line @typescript-eslint/no-empty-function
this.config.onChange = this.config.onChange || (() => {}); this.config.onReady = this.config.onReady || ((): void => {});
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.config.onChange = this.config.onChange || ((): void => {});
/** /**
* Initialize Blocks to pass data to the Renderer * Initialize Blocks to pass data to the Renderer
@ -206,7 +210,7 @@ export default class Core {
* *
* @returns {EditorConfig} * @returns {EditorConfig}
*/ */
get configuration(): EditorConfig|string { public get configuration(): EditorConfig|string {
return this.config; return this.config;
} }
@ -239,7 +243,7 @@ export default class Core {
* - make and save instances * - make and save instances
* - configure * - configure
*/ */
public init() { public init(): void {
/** /**
* Make modules instances and save it to the @property this.moduleInstances * Make modules instances and save it to the @property this.moduleInstances
*/ */
@ -256,9 +260,9 @@ export default class Core {
* *
* Get list of modules that needs to be prepared and return a sequence (Promise) * Get list of modules that needs to be prepared and return a sequence (Promise)
* *
* @returns {Promise} * @returns {Promise<void>}
*/ */
public async start() { public async start(): Promise<void> {
const modulesToPrepare = [ const modulesToPrepare = [
'Tools', 'Tools',
'UI', 'UI',
@ -327,7 +331,7 @@ export default class Core {
*/ */
private configureModules(): void { private configureModules(): void {
for (const name in this.moduleInstances) { for (const name in this.moduleInstances) {
if (this.moduleInstances.hasOwnProperty(name)) { if (Object.prototype.hasOwnProperty.call(this.moduleInstances, name)) {
/** /**
* Module does not need self-instance * Module does not need self-instance
*/ */

View file

@ -5,7 +5,7 @@ export default class Dom {
/** /**
* Check if passed tag has no closed tag * Check if passed tag has no closed tag
* *
* @param {HTMLElement} tag * @param {HTMLElement} tag - element to check
* @returns {boolean} * @returns {boolean}
*/ */
public static isSingleTag(tag: HTMLElement): boolean { public static isSingleTag(tag: HTMLElement): boolean {
@ -32,10 +32,10 @@ export default class Dom {
/** /**
* Check if element is BR or WBR * Check if element is BR or WBR
* *
* @param {HTMLElement} element * @param {HTMLElement} element - element to check
* @returns {boolean} * @returns {boolean}
*/ */
public static isLineBreakTag(element: HTMLElement) { public static isLineBreakTag(element: HTMLElement): element is HTMLBRElement {
return element && element.tagName && [ return element && element.tagName && [
'BR', 'BR',
'WBR', 'WBR',
@ -45,9 +45,10 @@ export default class Dom {
/** /**
* Helper for making Elements with classname and attributes * Helper for making Elements with classname and attributes
* *
* @param {string} tagName - new Element tag name * @param {string} tagName - new Element tag name
* @param {Array|string} classNames - list or name of CSS classname(s) * @param {string[]|string} [classNames] - list or name of CSS classname(s)
* @param {object} attributes - any attributes * @param {object} [attributes] - any attributes
*
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
public static make(tagName: string, classNames: string|string[] = null, attributes: object = {}): HTMLElement { public static make(tagName: string, classNames: string|string[] = null, attributes: object = {}): HTMLElement {
@ -60,7 +61,7 @@ export default class Dom {
} }
for (const attrName in attributes) { for (const attrName in attributes) {
if (attributes.hasOwnProperty(attrName)) { if (Object.prototype.hasOwnProperty.call(attributes, attrName)) {
el[attrName] = attributes[attrName]; el[attrName] = attributes[attrName];
} }
} }
@ -72,6 +73,7 @@ export default class Dom {
* Creates Text Node with the passed content * Creates Text Node with the passed content
* *
* @param {string} content - text content * @param {string} content - text content
*
* @returns {Text} * @returns {Text}
*/ */
public static text(content: string): Text { public static text(content: string): Text {
@ -82,8 +84,9 @@ export default class Dom {
* Creates SVG icon linked to the sprite * Creates SVG icon linked to the sprite
* *
* @param {string} name - name (id) of icon from sprite * @param {string} name - name (id) of icon from sprite
* @param {number} width * @param {number} [width] - icon width
* @param {number} height * @param {number} [height] - icon height
*
* @returns {SVGElement} * @returns {SVGElement}
*/ */
public static svg(name: string, width = 14, height = 14): SVGElement { public static svg(name: string, width = 14, height = 14): SVGElement {
@ -100,8 +103,8 @@ export default class Dom {
/** /**
* Append one or several elements to the parent * Append one or several elements to the parent
* *
* @param {Element|DocumentFragment} parent - where to append * @param {Element|DocumentFragment} parent - where to append
* @param {Element|Element[]|Text|Text[]} elements - element or elements list * @param {Element|Element[]|DocumentFragment|Text|Text[]} elements - element or elements list
*/ */
public static append( public static append(
parent: Element|DocumentFragment, parent: Element|DocumentFragment,
@ -170,10 +173,10 @@ export default class Dom {
/** /**
* Get Element by Id * Get Element by Id
* *
* @param {string} id * @param {string} id - id to find
* @returns {HTMLElement | null} * @returns {HTMLElement | null}
*/ */
public static get(id: string): HTMLElement { public static get(id: string): HTMLElement | null {
return document.getElementById(id); return document.getElementById(id);
} }
@ -182,8 +185,9 @@ export default class Dom {
* *
* Returns all matches * Returns all matches
* *
* @param {Element} el - element we searching inside. Default - DOM Document * @param {Element|Document} el - element we searching inside. Default - DOM Document
* @param {string} selector - searching string * @param {string} selector - searching string
*
* @returns {NodeList} * @returns {NodeList}
*/ */
public static findAll(el: Element|Document = document, selector: string): NodeList { public static findAll(el: Element|Document = document, selector: string): NodeList {
@ -198,7 +202,8 @@ export default class Dom {
* *
* @param {Node} node - root Node. From this vertex we start Deep-first search * @param {Node} node - root Node. From this vertex we start Deep-first search
* {@link https://en.wikipedia.org/wiki/Depth-first_search} * {@link https://en.wikipedia.org/wiki/Depth-first_search}
* @param {boolean} atLast - find last text node * @param {boolean} [atLast] - find last text node
*
* @returns {Node} - it can be text Node or Element Node, so that caret will able to work with it * @returns {Node} - it can be text Node or Element Node, so that caret will able to work with it
*/ */
public static getDeepestNode(node: Node, atLast = false): Node { public static getDeepestNode(node: Node, atLast = false): Node {
@ -250,9 +255,11 @@ export default class Dom {
/** /**
* Check if object is DOM node * Check if object is DOM node
* *
* @param {object} node * @param {*} node - object to check
*
* @returns {boolean} * @returns {boolean}
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public static isElement(node: any): node is Element { public static isElement(node: any): node is Element {
return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE; return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;
} }
@ -260,17 +267,19 @@ export default class Dom {
/** /**
* Check if object is DocumentFragmemt node * Check if object is DocumentFragmemt node
* *
* @param {object} node * @param {object} node - object to check
* @returns {boolean} * @returns {boolean}
*/ */
public static isFragment(node: any): boolean { // eslint-disable-next-line @typescript-eslint/no-explicit-any
public static isFragment(node: any): node is DocumentFragment {
return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE; return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
} }
/** /**
* Check if passed element is contenteditable * Check if passed element is contenteditable
* *
* @param {HTMLElement} element * @param {HTMLElement} element - html element to check
*
* @returns {boolean} * @returns {boolean}
*/ */
public static isContentEditable(element: HTMLElement): boolean { public static isContentEditable(element: HTMLElement): boolean {
@ -280,10 +289,12 @@ export default class Dom {
/** /**
* Checks target if it is native input * Checks target if it is native input
* *
* @param {Element|string|Node} target - HTML element or string * @param {*} target - HTML element or string
*
* @returns {boolean} * @returns {boolean}
*/ */
public static isNativeInput(target: any): boolean { // eslint-disable-next-line @typescript-eslint/no-explicit-any
public static isNativeInput(target: any): target is HTMLInputElement | HTMLTextAreaElement {
const nativeInputs = [ const nativeInputs = [
'INPUT', 'INPUT',
'TEXTAREA', 'TEXTAREA',
@ -295,16 +306,15 @@ export default class Dom {
/** /**
* Checks if we can set caret * Checks if we can set caret
* *
* @param {HTMLElement} target * @param {HTMLElement} target - target to check
*
* @returns {boolean} * @returns {boolean}
*/ */
public static canSetCaret(target: HTMLElement): boolean { public static canSetCaret(target: HTMLElement): boolean {
let result = true; let result = true;
if (Dom.isNativeInput(target)) { if (Dom.isNativeInput(target)) {
const inputElement = target as HTMLInputElement; switch (target.type) {
switch (inputElement.type) {
case 'file': case 'file':
case 'checkbox': case 'checkbox':
case 'radio': case 'radio':
@ -329,7 +339,8 @@ export default class Dom {
* @description Method checks simple Node without any childs for emptiness * @description Method checks simple Node without any childs for emptiness
* If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method * If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method
* *
* @param {Node} node * @param {Node} node - node to check
*
* @returns {boolean} true if it is empty * @returns {boolean} true if it is empty
*/ */
public static isNodeEmpty(node: Node): boolean { public static isNodeEmpty(node: Node): boolean {
@ -351,7 +362,8 @@ export default class Dom {
/** /**
* checks node if it is doesn't have any child nodes * checks node if it is doesn't have any child nodes
* *
* @param {Node} node * @param {Node} node - node to check
*
* @returns {boolean} * @returns {boolean}
*/ */
public static isLeaf(node: Node): boolean { public static isLeaf(node: Node): boolean {
@ -368,7 +380,7 @@ export default class Dom {
* *
* @description Pushes to stack all DOM leafs and checks for emptiness * @description Pushes to stack all DOM leafs and checks for emptiness
* *
* @param {Node} node * @param {Node} node - node to check
* @returns {boolean} * @returns {boolean}
*/ */
public static isEmpty(node: Node): boolean { public static isEmpty(node: Node): boolean {
@ -414,7 +426,7 @@ export default class Dom {
} }
/** /**
* If one of childs is not empty, checked Node is not empty too * If one of child is not empty, checked Node is not empty too
*/ */
if (node && !this.isNodeEmpty(node)) { if (node && !this.isNodeEmpty(node)) {
return false; return false;
@ -427,8 +439,9 @@ export default class Dom {
/** /**
* Check if string contains html elements * Check if string contains html elements
* *
* @param {string} str - string to check
*
* @returns {boolean} * @returns {boolean}
* @param {string} str
*/ */
public static isHTMLString(str: string): boolean { public static isHTMLString(str: string): boolean {
const wrapper = Dom.make('div'); const wrapper = Dom.make('div');
@ -441,7 +454,8 @@ export default class Dom {
/** /**
* Return length of node`s text content * Return length of node`s text content
* *
* @param {Node} node * @param {Node} node - node with content
*
* @returns {number} * @returns {number}
*/ */
public static getContentLength(node: Node): number { public static getContentLength(node: Node): number {
@ -461,7 +475,7 @@ export default class Dom {
* *
* @returns {string[]} * @returns {string[]}
*/ */
static get blockElements(): string[] { public static get blockElements(): string[] {
return [ return [
'address', 'address',
'article', 'article',
@ -507,6 +521,7 @@ export default class Dom {
* Check if passed content includes only inline elements * Check if passed content includes only inline elements
* *
* @param {string|HTMLElement} data - element or html string * @param {string|HTMLElement} data - element or html string
*
* @returns {boolean} * @returns {boolean}
*/ */
public static containsOnlyInlineElements(data: string | HTMLElement): boolean { public static containsOnlyInlineElements(data: string | HTMLElement): boolean {
@ -519,7 +534,7 @@ export default class Dom {
wrapper = data; wrapper = data;
} }
const check = (element: HTMLElement) => { const check = (element: HTMLElement): boolean => {
return !Dom.blockElements.includes(element.tagName.toLowerCase()) && return !Dom.blockElements.includes(element.tagName.toLowerCase()) &&
Array.from(element.children).every(check); Array.from(element.children).every(check);
}; };
@ -530,7 +545,7 @@ export default class Dom {
/** /**
* Find and return all block elements in the passed parent (including subtree) * Find and return all block elements in the passed parent (including subtree)
* *
* @param {HTMLElement} parent * @param {HTMLElement} parent - root element
* *
* @returns {HTMLElement[]} * @returns {HTMLElement[]}
*/ */
@ -547,7 +562,9 @@ export default class Dom {
/** /**
* Helper for get holder from {string} or return HTMLElement * Helper for get holder from {string} or return HTMLElement
* *
* @param element * @param {string | HTMLElement} element - holder's id or holder's HTML Element
*
* @returns {HTMLElement}
*/ */
public static getHolder(element: string | HTMLElement): HTMLElement { public static getHolder(element: string | HTMLElement): HTMLElement {
if (typeof element === 'string') { if (typeof element === 'string') {
@ -561,6 +578,8 @@ export default class Dom {
* Method checks passed Node if it is some extension Node * Method checks passed Node if it is some extension Node
* *
* @param {Node} node - any node * @param {Node} node - any node
*
* @returns {boolean}
*/ */
public static isExtensionNode(node: Node): boolean { public static isExtensionNode(node: Node): boolean {
const extensions = [ const extensions = [
@ -573,9 +592,11 @@ export default class Dom {
/** /**
* Returns true if element is anchor (is A tag) * Returns true if element is anchor (is A tag)
* *
* @param element * @param {Element} element - element to check
*
* @returns {boolean}
*/ */
public static isAnchor(element: Element): boolean { public static isAnchor(element: Element): element is HTMLAnchorElement {
return element.tagName.toLowerCase() === 'a'; return element.tagName.toLowerCase() === 'a';
} }
} }

View file

@ -61,7 +61,7 @@ export default class DomIterator {
/** /**
* Sets items. Can be used when iterable items changed dynamically * Sets items. Can be used when iterable items changed dynamically
* *
* @param {HTMLElement[]} nodeList * @param {HTMLElement[]} nodeList - nodes to iterate
*/ */
public setItems(nodeList: HTMLElement[]): void { public setItems(nodeList: HTMLElement[]): void {
this.items = nodeList; this.items = nodeList;

View file

@ -3,6 +3,8 @@ import * as _ from './utils';
/** /**
* Flipper construction options * Flipper construction options
*
* @interface FlipperOptions
*/ */
export interface FlipperOptions { export interface FlipperOptions {
/** /**
@ -66,7 +68,6 @@ export default class Flipper {
* @class * @class
* *
* @param {FlipperOptions} options - different constructing settings * @param {FlipperOptions} options - different constructing settings
* @
*/ */
constructor(options: FlipperOptions) { constructor(options: FlipperOptions) {
this.allowArrows = typeof options.allowArrows === 'boolean' ? options.allowArrows : true; this.allowArrows = typeof options.allowArrows === 'boolean' ? options.allowArrows : true;
@ -115,7 +116,7 @@ export default class Flipper {
/** /**
* Array of keys (codes) that is handled by Flipper * Array of keys (codes) that is handled by Flipper
* Used to: * Used to:
* - preventDefault only for this keys, not all keywdowns (@see constructor) * - preventDefault only for this keys, not all keydowns (@see constructor)
* - to skip external behaviours only for these keys, when filler is activated (@see BlockEvents@arrowRightAndDown) * - to skip external behaviours only for these keys, when filler is activated (@see BlockEvents@arrowRightAndDown)
*/ */
public static get usedKeys(): number[] { public static get usedKeys(): number[] {
@ -180,7 +181,7 @@ export default class Flipper {
* This function is fired before handling flipper keycodes * This function is fired before handling flipper keycodes
* The result of this function defines if it is need to be handled or not * The result of this function defines if it is need to be handled or not
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - keydown keyboard event
* @returns {boolean} * @returns {boolean}
*/ */
private isEventReadyForHandling(event: KeyboardEvent): boolean { private isEventReadyForHandling(event: KeyboardEvent): boolean {
@ -208,7 +209,7 @@ export default class Flipper {
/** /**
* When flipper is activated tab press will leaf the items * When flipper is activated tab press will leaf the items
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - tab keydown event
*/ */
private handleTabPress(event: KeyboardEvent): void { private handleTabPress(event: KeyboardEvent): void {
/** this property defines leaf direction */ /** this property defines leaf direction */
@ -242,7 +243,7 @@ export default class Flipper {
/** /**
* Enter press will click current item if flipper is activated * Enter press will click current item if flipper is activated
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - enter keydown event
*/ */
private handleEnterPress(event: KeyboardEvent): void { private handleEnterPress(event: KeyboardEvent): void {
if (!this.activated) { if (!this.activated) {

View file

@ -1,5 +1,5 @@
import $ from '../dom'; import $ from '../dom';
import { API, InlineTool, SanitizerConfig } from '../../../types'; import { InlineTool, SanitizerConfig } from '../../../types';
/** /**
* Bold Tool * Bold Tool
@ -27,7 +27,7 @@ export default class BoldInlineTool implements InlineTool {
* *
* @returns {object} * @returns {object}
*/ */
static get sanitize(): SanitizerConfig { public static get sanitize(): SanitizerConfig {
return { return {
b: {}, b: {},
} as SanitizerConfig; } as SanitizerConfig;
@ -69,7 +69,7 @@ export default class BoldInlineTool implements InlineTool {
/** /**
* Wrap range with <b> tag * Wrap range with <b> tag
* *
* @param {Range} range * @param {Range} range - range to wrap
*/ */
public surround(range: Range): void { public surround(range: Range): void {
document.execCommand(this.commandName); document.execCommand(this.commandName);
@ -78,7 +78,9 @@ export default class BoldInlineTool implements InlineTool {
/** /**
* Check selection and set activated state to button if there are <b> tag * Check selection and set activated state to button if there are <b> tag
* *
* @param {Selection} selection * @param {Selection} selection - selection to check
*
* @returns {boolean}
*/ */
public checkState(selection: Selection): boolean { public checkState(selection: Selection): boolean {
const isActive = document.queryCommandState(this.commandName); const isActive = document.queryCommandState(this.commandName);
@ -90,6 +92,8 @@ export default class BoldInlineTool implements InlineTool {
/** /**
* Set a shortcut * Set a shortcut
*
* @returns {boolean}
*/ */
public get shortcut(): string { public get shortcut(): string {
return 'CMD+B'; return 'CMD+B';

View file

@ -27,7 +27,7 @@ export default class ItalicInlineTool implements InlineTool {
* *
* @returns {object} * @returns {object}
*/ */
static get sanitize(): SanitizerConfig { public static get sanitize(): SanitizerConfig {
return { return {
i: {}, i: {},
} as SanitizerConfig; } as SanitizerConfig;
@ -69,7 +69,7 @@ export default class ItalicInlineTool implements InlineTool {
/** /**
* Wrap range with <i> tag * Wrap range with <i> tag
* *
* @param {Range} range * @param {Range} range - range to wrap
*/ */
public surround(range: Range): void { public surround(range: Range): void {
document.execCommand(this.commandName); document.execCommand(this.commandName);
@ -78,7 +78,7 @@ export default class ItalicInlineTool implements InlineTool {
/** /**
* Check selection and set activated state to button if there are <i> tag * Check selection and set activated state to button if there are <i> tag
* *
* @param {Selection} selection * @param {Selection} selection - selection to check
*/ */
public checkState(selection: Selection): boolean { public checkState(selection: Selection): boolean {
const isActive = document.queryCommandState(this.commandName); const isActive = document.queryCommandState(this.commandName);

View file

@ -31,7 +31,7 @@ export default class LinkInlineTool implements InlineTool {
* *
* @returns {object} * @returns {object}
*/ */
static get sanitize(): SanitizerConfig { public static get sanitize(): SanitizerConfig {
return { return {
a: { a: {
href: true, href: true,
@ -101,7 +101,7 @@ export default class LinkInlineTool implements InlineTool {
private notifier: Notifier; private notifier: Notifier;
/** /**
* @param {{api: API}} - Editor.js API * @param {API} api - Editor.js API
*/ */
constructor({ api }) { constructor({ api }) {
this.toolbar = api.toolbar; this.toolbar = api.toolbar;
@ -142,7 +142,7 @@ export default class LinkInlineTool implements InlineTool {
/** /**
* Handle clicks on the Inline Toolbar icon * Handle clicks on the Inline Toolbar icon
* *
* @param {Range} range * @param {Range} range - range to wrap with link
*/ */
public surround(range: Range): void { public surround(range: Range): void {
/** /**
@ -182,7 +182,7 @@ export default class LinkInlineTool implements InlineTool {
/** /**
* Check selection and set activated state to button if there are <a> tag * Check selection and set activated state to button if there are <a> tag
* *
* @param {Selection} selection * @param {Selection} selection - selection to check
*/ */
public checkState(selection?: Selection): boolean { public checkState(selection?: Selection): boolean {
const anchorTag = this.selection.findParentTag('A'); const anchorTag = this.selection.findParentTag('A');
@ -275,7 +275,7 @@ export default class LinkInlineTool implements InlineTool {
/** /**
* Enter pressed on input * Enter pressed on input
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - enter keydown event
*/ */
private enterPressed(event: KeyboardEvent): void { private enterPressed(event: KeyboardEvent): void {
let value = this.nodes.input.value || ''; let value = this.nodes.input.value || '';
@ -318,7 +318,7 @@ export default class LinkInlineTool implements InlineTool {
/** /**
* Detects if passed string is URL * Detects if passed string is URL
* *
* @param {string} str * @param {string} str - string to validate
* @returns {boolean} * @returns {boolean}
*/ */
private validateURL(str: string): boolean { private validateURL(str: string): boolean {
@ -345,7 +345,7 @@ export default class LinkInlineTool implements InlineTool {
/** /**
* Add 'http' protocol to the links like 'vc.ru', 'google.com' * Add 'http' protocol to the links like 'vc.ru', 'google.com'
* *
* @param {string} link * @param {string} link - string to process
*/ */
private addProtocol(link: string): string { private addProtocol(link: string): string {
/** /**

View file

@ -14,19 +14,19 @@ export default class BlocksAPI extends Module {
* *
* @returns {Blocks} * @returns {Blocks}
*/ */
get methods(): Blocks { public get methods(): Blocks {
return { return {
clear: () => this.clear(), clear: (): void => this.clear(),
render: (data: OutputData) => this.render(data), render: (data: OutputData): Promise<void> => this.render(data),
renderFromHTML: (data: string) => this.renderFromHTML(data), renderFromHTML: (data: string): Promise<void> => this.renderFromHTML(data),
delete: () => this.delete(), delete: (): void => this.delete(),
swap: (fromIndex: number, toIndex: number) => this.swap(fromIndex, toIndex), swap: (fromIndex: number, toIndex: number): void => this.swap(fromIndex, toIndex),
move: (toIndex: number, fromIndex?: number) => this.move(toIndex, fromIndex), move: (toIndex: number, fromIndex?: number): void => this.move(toIndex, fromIndex),
getBlockByIndex: (index: number) => this.getBlockByIndex(index), getBlockByIndex: (index: number): HTMLElement => this.getBlockByIndex(index),
getCurrentBlockIndex: () => this.getCurrentBlockIndex(), getCurrentBlockIndex: (): number => this.getCurrentBlockIndex(),
getBlocksCount: () => this.getBlocksCount(), getBlocksCount: (): number => this.getBlocksCount(),
stretchBlock: (index: number, status = true) => this.stretchBlock(index, status), stretchBlock: (index: number, status = true): void => this.stretchBlock(index, status),
insertNewBlock: () => this.insertNewBlock(), insertNewBlock: (): void => this.insertNewBlock(),
insert: this.insert, insert: this.insert,
}; };
} }
@ -52,7 +52,7 @@ export default class BlocksAPI extends Module {
/** /**
* Returns Block holder by Block index * Returns Block holder by Block index
* *
* @param {number} index * @param {number} index - index to get
* *
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
@ -82,8 +82,8 @@ export default class BlocksAPI extends Module {
/** /**
* Move block from one index to another * Move block from one index to another
* *
* @param {number} toIndex * @param {number} toIndex - index to move to
* @param {number} fromIndex * @param {number} fromIndex - index to move from
*/ */
public move(toIndex: number, fromIndex?: number): void { public move(toIndex: number, fromIndex?: number): void {
this.Editor.BlockManager.move(toIndex, fromIndex); this.Editor.BlockManager.move(toIndex, fromIndex);
@ -98,7 +98,7 @@ export default class BlocksAPI extends Module {
/** /**
* Deletes Block * Deletes Block
* *
* @param blockIndex * @param {number} blockIndex - index of Block to delete
*/ */
public delete(blockIndex?: number): void { public delete(blockIndex?: number): void {
this.Editor.BlockManager.removeBlock(blockIndex); this.Editor.BlockManager.removeBlock(blockIndex);
@ -141,7 +141,7 @@ export default class BlocksAPI extends Module {
/** /**
* Render passed HTML string * Render passed HTML string
* *
* @param {string} data * @param {string} data - HTML string to render
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
public renderFromHTML(data: string): Promise<void> { public renderFromHTML(data: string): Promise<void> {
@ -153,7 +153,7 @@ export default class BlocksAPI extends Module {
/** /**
* Stretch Block's content * Stretch Block's content
* *
* @param {number} index * @param {number} index - index of Block to stretch
* @param {boolean} status - true to enable, false to disable * @param {boolean} status - true to enable, false to disable
*/ */
public stretchBlock(index: number, status = true): void { public stretchBlock(index: number, status = true): void {
@ -189,13 +189,13 @@ export default class BlocksAPI extends Module {
index, index,
needToFocus needToFocus
); );
} };
/** /**
* Insert new Block * Insert new Block
* After set caret to this Block * After set caret to this Block
* *
* @todo: remove in 3.0.0 * @todo remove in 3.0.0
* *
* @deprecated with insert() method * @deprecated with insert() method
*/ */

View file

@ -11,7 +11,7 @@ export default class CaretAPI extends Module {
* *
* @returns {Caret} * @returns {Caret}
*/ */
get methods(): Caret { public get methods(): Caret {
return { return {
setToFirstBlock: this.setToFirstBlock, setToFirstBlock: this.setToFirstBlock,
setToLastBlock: this.setToLastBlock, setToLastBlock: this.setToLastBlock,
@ -127,7 +127,7 @@ export default class CaretAPI extends Module {
* *
* @returns {boolean} * @returns {boolean}
*/ */
private focus = (atEnd = false) => { private focus = (atEnd = false): boolean => {
if (atEnd) { if (atEnd) {
return this.setToLastBlock(this.Editor.Caret.positions.END); return this.setToLastBlock(this.Editor.Caret.positions.END);
} }

View file

@ -11,19 +11,19 @@ export default class EventsAPI extends Module {
* *
* @returns {Events} * @returns {Events}
*/ */
get methods(): Events { public get methods(): Events {
return { return {
emit: (eventName: string, data: object) => this.emit(eventName, data), emit: (eventName: string, data: object): void => this.emit(eventName, data),
off: (eventName: string, callback: () => void) => this.off(eventName, callback), off: (eventName: string, callback: () => void): void => this.off(eventName, callback),
on: (eventName: string, callback: () => void) => this.on(eventName, callback), on: (eventName: string, callback: () => void): void => this.on(eventName, callback),
}; };
} }
/** /**
* Subscribe on Events * Subscribe on Events
* *
* @param {string} eventName * @param {string} eventName - event name to subscribe
* @param {Function} callback * @param {Function} callback - event handler
*/ */
public on(eventName, callback): void { public on(eventName, callback): void {
this.Editor.Events.on(eventName, callback); this.Editor.Events.on(eventName, callback);
@ -32,8 +32,8 @@ export default class EventsAPI extends Module {
/** /**
* Emit event with data * Emit event with data
* *
* @param {string} eventName * @param {string} eventName - event to emit
* @param {object} data * @param {object} data - event's data
*/ */
public emit(eventName, data): void { public emit(eventName, data): void {
this.Editor.Events.emit(eventName, data); this.Editor.Events.emit(eventName, data);
@ -42,8 +42,8 @@ export default class EventsAPI extends Module {
/** /**
* Unsubscribe from Event * Unsubscribe from Event
* *
* @param {string} eventName * @param {string} eventName - event to unsubscribe
* @param {Function} callback * @param {Function} callback - event handler
*/ */
public off(eventName, callback): void { public off(eventName, callback): void {
this.Editor.Events.off(eventName, callback); this.Editor.Events.off(eventName, callback);

View file

@ -11,10 +11,10 @@ export default class InlineToolbarAPI extends Module {
* *
* @returns {InlineToolbar} * @returns {InlineToolbar}
*/ */
get methods(): InlineToolbar { public get methods(): InlineToolbar {
return { return {
close: () => this.close(), close: (): void => this.close(),
open: () => this.open(), open: (): void => this.open(),
}; };
} }

View file

@ -11,20 +11,20 @@ export default class ListenersAPI extends Module {
* *
* @returns {Listeners} * @returns {Listeners}
*/ */
get methods(): Listeners { public get methods(): Listeners {
return { return {
on: (element: HTMLElement, eventType, handler, useCapture) => this.on(element, eventType, handler, useCapture), on: (element: HTMLElement, eventType, handler, useCapture): void => this.on(element, eventType, handler, useCapture),
off: (element, eventType, handler) => this.off(element, eventType, handler), off: (element, eventType, handler, useCapture): void => this.off(element, eventType, handler, useCapture),
}; };
} }
/** /**
* adds DOM event listener * adds DOM event listener
* *
* @param {HTMLElement} element * @param {HTMLElement} element - Element to set handler to
* @param {string} eventType * @param {string} eventType - event type
* @param {() => void} handler * @param {() => void} handler - event handler
* @param {boolean} useCapture * @param {boolean} useCapture - capture event or not
*/ */
public on(element: HTMLElement, eventType: string, handler: () => void, useCapture?: boolean): void { public on(element: HTMLElement, eventType: string, handler: () => void, useCapture?: boolean): void {
this.Editor.Listeners.on(element, eventType, handler, useCapture); this.Editor.Listeners.on(element, eventType, handler, useCapture);
@ -33,11 +33,12 @@ export default class ListenersAPI extends Module {
/** /**
* Removes DOM listener from element * Removes DOM listener from element
* *
* @param element * @param {Element} element - Element to remove handler from
* @param eventType * @param eventType - event type
* @param handler * @param handler - event handler
* @param {boolean} useCapture - capture event or not
*/ */
public off(element, eventType, handler): void { public off(element: Element, eventType: string, handler: () => void, useCapture?: boolean): void {
this.Editor.Listeners.off(element, eventType, handler); this.Editor.Listeners.off(element, eventType, handler, useCapture);
} }
} }

View file

@ -9,15 +9,16 @@ export default class NotifierAPI extends Module {
/** /**
* Available methods * Available methods
*/ */
get methods(): Notifier { public get methods(): Notifier {
return { return {
show: (options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions) => this.show(options), show: (options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void => this.show(options),
}; };
} }
/** /**
* Show notification * Show notification
* @param options *
* @param {NotifierOptions} options - message option
*/ */
public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void { public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void {
return this.Editor.Notifier.show(options); return this.Editor.Notifier.show(options);

View file

@ -1,5 +1,6 @@
import Module from '../../__module'; import Module from '../../__module';
import { Sanitizer } from '../../../../types/api'; import { Sanitizer } from '../../../../types/api';
import { SanitizerConfig } from '../../../../types/configs';
/** /**
* @class SanitizerAPI * @class SanitizerAPI
@ -11,18 +12,21 @@ export default class SanitizerAPI extends Module {
* *
* @returns {Sanitizer} * @returns {Sanitizer}
*/ */
get methods(): Sanitizer { public get methods(): Sanitizer {
return { return {
clean: (taintString, config) => this.clean(taintString, config), clean: (taintString, config): string => this.clean(taintString, config),
}; };
} }
/** /**
* Perform sanitizing of a string * Perform sanitizing of a string
* @param taintString - what to sanitize *
* @param config - sanitizer config * @param {string} taintString - what to sanitize
* @param {SanitizerConfig} config - sanitizer config
*
* @returns {string}
*/ */
public clean(taintString, config) { public clean(taintString: string, config: SanitizerConfig): string {
return this.Editor.Sanitizer.clean(taintString, config); return this.Editor.Sanitizer.clean(taintString, config);
} }
} }

View file

@ -12,9 +12,9 @@ export default class SaverAPI extends Module {
* *
* @returns {Saver} * @returns {Saver}
*/ */
get methods(): Saver { public get methods(): Saver {
return { return {
save: () => this.save(), save: (): Promise<OutputData> => this.save(),
}; };
} }

View file

@ -14,8 +14,8 @@ export default class SelectionAPI extends Module {
*/ */
public get methods(): SelectionAPIInterface { public get methods(): SelectionAPIInterface {
return { return {
findParentTag: (tagName: string, className?: string) => this.findParentTag(tagName, className), findParentTag: (tagName: string, className?: string): HTMLElement | null => this.findParentTag(tagName, className),
expandToTag: (node: HTMLElement) => this.expandToTag(node), expandToTag: (node: HTMLElement): void => this.expandToTag(node),
}; };
} }
@ -24,9 +24,10 @@ export default class SelectionAPI extends Module {
* *
* @param {string} tagName - tag to find * @param {string} tagName - tag to find
* @param {string} className - tag's class name * @param {string} className - tag's class name
*
* @returns {HTMLElement|null} * @returns {HTMLElement|null}
*/ */
public findParentTag(tagName: string, className?: string): HTMLElement|null { public findParentTag(tagName: string, className?: string): HTMLElement | null {
return new SelectionUtils().findParentTag(tagName, className); return new SelectionUtils().findParentTag(tagName, className);
} }

View file

@ -11,10 +11,10 @@ export default class ToolbarAPI extends Module {
* *
* @returns {Toolbar} * @returns {Toolbar}
*/ */
get methods(): Toolbar { public get methods(): Toolbar {
return { return {
close: () => this.close(), close: (): void => this.close(),
open: () => this.open(), open: (): void => this.open(),
}; };
} }

View file

@ -10,46 +10,46 @@ export default class TooltipAPI extends Module {
/** /**
* Available methods * Available methods
*/ */
get methods(): Tooltip { public get methods(): Tooltip {
return { return {
show: (element: HTMLElement, show: (element: HTMLElement,
content: TooltipContent, content: TooltipContent,
options?: TooltipOptions options?: TooltipOptions
) => this.show(element, content, options), ): void => this.show(element, content, options),
hide: () => this.hide(), hide: (): void => this.hide(),
onHover: (element: HTMLElement, onHover: (element: HTMLElement,
content: TooltipContent, content: TooltipContent,
options?: TooltipOptions options?: TooltipOptions
) => this.onHover(element, content, options), ): void => this.onHover(element, content, options),
}; };
} }
/** /**
* Method show tooltip on element with passed HTML content * Method show tooltip on element with passed HTML content
* *
* @param {HTMLElement} element * @param {HTMLElement} element - element on which tooltip should be shown
* @param {TooltipContent} content * @param {TooltipContent} content - tooltip content
* @param {TooltipOptions} options * @param {TooltipOptions} options - tooltip options
*/ */
public show(element: HTMLElement, content: TooltipContent, options?: TooltipOptions) { public show(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void {
this.Editor.Tooltip.show(element, content, options); this.Editor.Tooltip.show(element, content, options);
} }
/** /**
* Method hides tooltip on HTML page * Method hides tooltip on HTML page
*/ */
public hide() { public hide(): void {
this.Editor.Tooltip.hide(); this.Editor.Tooltip.hide();
} }
/** /**
* Decorator for showing Tooltip by mouseenter/mouseleave * Decorator for showing Tooltip by mouseenter/mouseleave
* *
* @param {HTMLElement} element * @param {HTMLElement} element - element on which tooltip should be shown
* @param {TooltipContent} content * @param {TooltipContent} content - tooltip content
* @param {TooltipOptions} options * @param {TooltipOptions} options - tooltip options
*/ */
public onHover(element: HTMLElement, content: TooltipContent, options?: TooltipOptions) { public onHover(element: HTMLElement, content: TooltipContent, options?: TooltipOptions): void {
this.Editor.Tooltip.onHover(element, content, options); this.Editor.Tooltip.onHover(element, content, options);
} }
} }

View file

@ -95,7 +95,7 @@ export default class BlockEvents extends Module {
* - shows Inline Toolbar if something selected * - shows Inline Toolbar if something selected
* - shows conversion toolbar with 85% of block selection * - shows conversion toolbar with 85% of block selection
* *
* @param event * @param {KeyboardEvent} event - keyup event
*/ */
public keyup(event): void { public keyup(event): void {
/** /**
@ -114,7 +114,7 @@ export default class BlockEvents extends Module {
/** /**
* Set up mouse selection handlers * Set up mouse selection handlers
* *
* @param {MouseEvent} event * @param {MouseEvent} event - mouse down event
*/ */
public mouseDown(event: MouseEvent): void { public mouseDown(event: MouseEvent): void {
/** /**
@ -129,7 +129,7 @@ export default class BlockEvents extends Module {
/** /**
* Open Toolbox to leaf Tools * Open Toolbox to leaf Tools
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - tab keydown event
*/ */
public tabPressed(event): void { public tabPressed(event): void {
/** /**
@ -162,7 +162,7 @@ export default class BlockEvents extends Module {
* Escape pressed * Escape pressed
* If some of Toolbar components are opened, then close it otherwise close Toolbar * If some of Toolbar components are opened, then close it otherwise close Toolbar
* *
* @param {Event} event * @param {Event} event - escape keydown event
*/ */
public escapePressed(event): void { public escapePressed(event): void {
/** /**
@ -186,9 +186,9 @@ export default class BlockEvents extends Module {
/** /**
* Add drop target styles * Add drop target styles
* *
* @param {DragEvent} e * @param {DragEvent} e - drag over event
*/ */
public dragOver(e: DragEvent) { public dragOver(e: DragEvent): void {
const block = this.Editor.BlockManager.getBlockByChildNode(e.target as Node); const block = this.Editor.BlockManager.getBlockByChildNode(e.target as Node);
block.dropTarget = true; block.dropTarget = true;
@ -197,9 +197,9 @@ export default class BlockEvents extends Module {
/** /**
* Remove drop target style * Remove drop target style
* *
* @param {DragEvent} e * @param {DragEvent} e - drag leave event
*/ */
public dragLeave(e: DragEvent) { public dragLeave(e: DragEvent): void {
const block = this.Editor.BlockManager.getBlockByChildNode(e.target as Node); const block = this.Editor.BlockManager.getBlockByChildNode(e.target as Node);
block.dropTarget = false; block.dropTarget = false;
@ -209,7 +209,7 @@ export default class BlockEvents extends Module {
* Copying selected blocks * Copying selected blocks
* Before putting to the clipboard we sanitize all blocks and then copy to the clipboard * Before putting to the clipboard we sanitize all blocks and then copy to the clipboard
* *
* @param {ClipboardEvent} event * @param {ClipboardEvent} event - clipboard event
*/ */
public handleCommandC(event: ClipboardEvent): void { public handleCommandC(event: ClipboardEvent): void {
const { BlockSelection } = this.Editor; const { BlockSelection } = this.Editor;
@ -225,7 +225,7 @@ export default class BlockEvents extends Module {
/** /**
* Copy and Delete selected Blocks * Copy and Delete selected Blocks
* *
* @param {ClipboardEvent} event * @param {ClipboardEvent} event - clipboard event
*/ */
public handleCommandX(event: ClipboardEvent): void { public handleCommandX(event: ClipboardEvent): void {
const { BlockSelection, BlockManager, Caret } = this.Editor; const { BlockSelection, BlockManager, Caret } = this.Editor;
@ -325,7 +325,7 @@ export default class BlockEvents extends Module {
/** /**
* Check if Block should be removed by current Backspace keydown * Check if Block should be removed by current Backspace keydown
*/ */
if (currentBlock.selected || currentBlock.isEmpty && currentBlock.currentInput === currentBlock.firstInput) { if (currentBlock.selected || (currentBlock.isEmpty && currentBlock.currentInput === currentBlock.firstInput)) {
event.preventDefault(); event.preventDefault();
const index = BlockManager.currentBlockIndex; const index = BlockManager.currentBlockIndex;
@ -384,7 +384,7 @@ export default class BlockEvents extends Module {
/** /**
* Merge current and previous Blocks if they have the same type * Merge current and previous Blocks if they have the same type
*/ */
private mergeBlocks() { private mergeBlocks(): void {
const { BlockManager, Caret, Toolbar } = this.Editor; const { BlockManager, Caret, Toolbar } = this.Editor;
const targetBlock = BlockManager.previousBlock; const targetBlock = BlockManager.previousBlock;
const blockToMerge = BlockManager.currentBlock; const blockToMerge = BlockManager.currentBlock;
@ -427,7 +427,7 @@ export default class BlockEvents extends Module {
/** /**
* Handle right and down keyboard keys * Handle right and down keyboard keys
* *
* @param event * @param {KeyboardEvent} event - keyboard event
*/ */
private arrowRightAndDown(event: KeyboardEvent): void { private arrowRightAndDown(event: KeyboardEvent): void {
const isFlipperCombination = Flipper.usedKeys.includes(event.keyCode) && const isFlipperCombination = Flipper.usedKeys.includes(event.keyCode) &&
@ -481,7 +481,7 @@ export default class BlockEvents extends Module {
/** /**
* Handle left and up keyboard keys * Handle left and up keyboard keys
* *
* @param event * @param {KeyboardEvent} event - keyboard event
*/ */
private arrowLeftAndUp(event: KeyboardEvent): void { private arrowLeftAndUp(event: KeyboardEvent): void {
/** /**
@ -536,9 +536,9 @@ export default class BlockEvents extends Module {
/** /**
* Cases when we need to close Toolbar * Cases when we need to close Toolbar
* *
* @param event * @param {KeyboardEvent} event - keyboard event
*/ */
private needToolbarClosing(event) { private needToolbarClosing(event: KeyboardEvent): boolean {
const toolboxItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.Toolbox.opened), const toolboxItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.Toolbox.opened),
blockSettingsItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.BlockSettings.opened), blockSettingsItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.BlockSettings.opened),
inlineToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.InlineToolbar.opened), inlineToolbarItemSelected = (event.keyCode === _.keyCodes.ENTER && this.Editor.InlineToolbar.opened),

View file

@ -31,7 +31,7 @@ export default class BlockManager extends Module {
/** /**
* Set current Block index and fire Block lifecycle callbacks * Set current Block index and fire Block lifecycle callbacks
* *
* @param newIndex * @param {number} newIndex - index of Block to set as current
*/ */
public set currentBlockIndex(newIndex: number) { public set currentBlockIndex(newIndex: number) {
if (this._blocks[this._currentBlockIndex]) { if (this._blocks[this._currentBlockIndex]) {
@ -163,7 +163,7 @@ export default class BlockManager extends Module {
* *
* @returns {Promise} * @returns {Promise}
*/ */
public async prepare() { public async prepare(): Promise<void> {
const blocks = new Blocks(this.Editor.UI.nodes.redactor); const blocks = new Blocks(this.Editor.UI.nodes.redactor);
const { BlockEvents, Listeners } = this.Editor; const { BlockEvents, Listeners } = this.Editor;
@ -252,7 +252,7 @@ export default class BlockManager extends Module {
/** /**
* Insert pasted content. Call onPaste callback after insert. * Insert pasted content. Call onPaste callback after insert.
* *
* @param {string} toolName * @param {string} toolName - name of Tool to insert
* @param {PasteEvent} pasteEvent - pasted data * @param {PasteEvent} pasteEvent - pasted data
* @param {boolean} replace - should replace current block * @param {boolean} replace - should replace current block
*/ */
@ -288,7 +288,7 @@ export default class BlockManager extends Module {
* *
* @returns {Block} inserted Block * @returns {Block} inserted Block
*/ */
public insertInitialBlockAtIndex(index: number, needToFocus = false) { public insertInitialBlockAtIndex(index: number, needToFocus = false): Block {
const block = this.composeBlock(this.config.initialBlock, {}, {}); const block = this.composeBlock(this.config.initialBlock, {}, {});
this._blocks[index] = block; this._blocks[index] = block;
@ -347,7 +347,7 @@ export default class BlockManager extends Module {
/** /**
* Remove block with passed index or remove last * Remove block with passed index or remove last
* *
* @param {number|null} index * @param {number|null} index - index of Block to remove
*/ */
public removeBlock(index?: number): void { public removeBlock(index?: number): void {
if (index === undefined) { if (index === undefined) {
@ -374,7 +374,7 @@ export default class BlockManager extends Module {
* Remove only selected Blocks * Remove only selected Blocks
* and returns first Block index where started removing... * and returns first Block index where started removing...
* *
* @returns number|undefined * @returns {number|undefined}
*/ */
public removeSelectedBlocks(): number|undefined { public removeSelectedBlocks(): number|undefined {
let firstSelectedBlockIndex; let firstSelectedBlockIndex;
@ -461,7 +461,8 @@ export default class BlockManager extends Module {
/** /**
* Returns Block by passed index * Returns Block by passed index
* *
* @param {number} index * @param {number} index - index to get
*
* @returns {Block} * @returns {Block}
*/ */
public getBlockByIndex(index): Block { public getBlockByIndex(index): Block {
@ -471,7 +472,8 @@ export default class BlockManager extends Module {
/** /**
* Get Block instance by html element * Get Block instance by html element
* *
* @param {Node} element * @param {Node} element - html element to get Block by
*
* @returns {Block} * @returns {Block}
*/ */
public getBlock(element: HTMLElement): Block { public getBlock(element: HTMLElement): Block {
@ -519,7 +521,7 @@ export default class BlockManager extends Module {
* 2) Mark it as current * 2) Mark it as current
* *
* @param {Node} childNode - look ahead from this node. * @param {Node} childNode - look ahead from this node.
* @param {string} caretPosition - position where to set caret *
* @throws Error - when passed Node is not included at the Block * @throws Error - when passed Node is not included at the Block
*/ */
public setCurrentBlockByChildNode(childNode: Node): Block { public setCurrentBlockByChildNode(childNode: Node): Block {
@ -549,7 +551,8 @@ export default class BlockManager extends Module {
/** /**
* Return block which contents passed node * Return block which contents passed node
* *
* @param {Node} childNode * @param {Node} childNode - node to get Block by
*
* @returns {Block} * @returns {Block}
*/ */
public getBlockByChildNode(childNode: Node): Block { public getBlockByChildNode(childNode: Node): Block {
@ -568,8 +571,9 @@ export default class BlockManager extends Module {
/** /**
* Swap Blocks Position * Swap Blocks Position
* *
* @param {number} fromIndex * @param {number} fromIndex - index of first block
* @param {number} toIndex * @param {number} toIndex - index of second block
*
* @deprecated use 'move' instead * @deprecated use 'move' instead
*/ */
public swap(fromIndex, toIndex): void { public swap(fromIndex, toIndex): void {
@ -583,8 +587,8 @@ export default class BlockManager extends Module {
/** /**
* Move a block to a new index * Move a block to a new index
* *
* @param {number} toIndex * @param {number} toIndex - index where to move Block
* @param {number} fromIndex * @param {number} fromIndex - index of Block to move
*/ */
public move(toIndex, fromIndex = this.currentBlockIndex): void { public move(toIndex, fromIndex = this.currentBlockIndex): void {
// make sure indexes are valid and within a valid range // make sure indexes are valid and within a valid range
@ -640,7 +644,7 @@ export default class BlockManager extends Module {
/** /**
* Bind Events * Bind Events
* *
* @param {object} block * @param {Block} block - Block to which event should be bound
*/ */
private bindEvents(block: Block): void { private bindEvents(block: Block): void {
const { BlockEvents, Listeners } = this.Editor; const { BlockEvents, Listeners } = this.Editor;
@ -656,12 +660,10 @@ export default class BlockManager extends Module {
* Validates that the given index is not lower than 0 or higher than the amount of blocks * 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 * @param {number} index - index of blocks array to validate
*
* @returns {boolean}
*/ */
private validateIndex(index: number): boolean { private validateIndex(index: number): boolean {
if (index < 0 || index >= this._blocks.length) { return !(index < 0 || index >= this._blocks.length);
return false;
}
return true;
} }
} }

View file

@ -11,6 +11,7 @@ import * as _ from '../utils';
import $ from '../dom'; import $ from '../dom';
import SelectionUtils from '../selection'; import SelectionUtils from '../selection';
import { SanitizerConfig } from '../../../types/configs';
/** /**
* *
@ -21,7 +22,7 @@ export default class BlockSelection extends Module {
* *
* @returns {SanitizerConfig} * @returns {SanitizerConfig}
*/ */
private get sanitizerConfig() { private get sanitizerConfig(): SanitizerConfig {
return { return {
p: {}, p: {},
h1: {}, h1: {},
@ -62,7 +63,7 @@ export default class BlockSelection extends Module {
/** /**
* Set selected all blocks * Set selected all blocks
* *
* @param {boolean} state * @param {boolean} state - state to set
*/ */
public set allBlocksSelected(state: boolean) { public set allBlocksSelected(state: boolean) {
const { BlockManager } = this.Editor; const { BlockManager } = this.Editor;
@ -160,7 +161,7 @@ export default class BlockSelection extends Module {
* *
* @param {number?} index - Block index according to the BlockManager's indexes * @param {number?} index - Block index according to the BlockManager's indexes
*/ */
public unSelectBlockByIndex(index?) { public unSelectBlockByIndex(index?): void {
const { BlockManager } = this.Editor; const { BlockManager } = this.Editor;
let block; let block;
@ -180,7 +181,7 @@ export default class BlockSelection extends Module {
* @param {Event} reason - event caused clear of selection * @param {Event} reason - event caused clear of selection
* @param {boolean} restoreSelection - if true, restore saved selection * @param {boolean} restoreSelection - if true, restore saved selection
*/ */
public clearSelection(reason?: Event, restoreSelection = false) { public clearSelection(reason?: Event, restoreSelection = false): void {
const { BlockManager, Caret, RectangleSelection } = this.Editor; const { BlockManager, Caret, RectangleSelection } = this.Editor;
this.needToSelectAll = false; this.needToSelectAll = false;
@ -226,7 +227,7 @@ export default class BlockSelection extends Module {
* *
* @param {ClipboardEvent} e - copy/cut event * @param {ClipboardEvent} e - copy/cut event
* *
* @returns Promise<void> * @returns {Promise<void>}
*/ */
public async copySelectedBlocks(e: ClipboardEvent): Promise<void> { public async copySelectedBlocks(e: ClipboardEvent): Promise<void> {
/** /**
@ -263,7 +264,7 @@ export default class BlockSelection extends Module {
* *
* @param {number?} index - Block index according to the BlockManager's indexes * @param {number?} index - Block index according to the BlockManager's indexes
*/ */
public selectBlockByIndex(index?) { public selectBlockByIndex(index?): void {
const { BlockManager } = this.Editor; const { BlockManager } = this.Editor;
/** /**
@ -294,7 +295,7 @@ export default class BlockSelection extends Module {
* First CMD+A selects all input content by native behaviour, * First CMD+A selects all input content by native behaviour,
* next CMD+A keypress selects all blocks * next CMD+A keypress selects all blocks
* *
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - keyboard event
*/ */
private handleCommandA(event: KeyboardEvent): void { private handleCommandA(event: KeyboardEvent): void {
this.Editor.RectangleSelection.clearSelection(); this.Editor.RectangleSelection.clearSelection();
@ -365,7 +366,7 @@ export default class BlockSelection extends Module {
* Select All Blocks * Select All Blocks
* Each Block has selected setter that makes Block copyable * Each Block has selected setter that makes Block copyable
*/ */
private selectAllBlocks() { private selectAllBlocks(): void {
/** /**
* Save selection * Save selection
* Will be restored when closeSelection fired * Will be restored when closeSelection fired

View file

@ -131,7 +131,7 @@ export default class Caret extends Module {
* We use <= comparison for case: * We use <= comparison for case:
* "| Hello" <--- selection.anchorOffset is 0, but firstLetterPosition is 1 * "| Hello" <--- selection.anchorOffset is 0, but firstLetterPosition is 1
*/ */
return firstNode === null || focusNode === firstNode && focusOffset <= firstLetterPosition; return firstNode === null || (focusNode === firstNode && focusOffset <= firstLetterPosition);
} }
/** /**
@ -191,7 +191,7 @@ export default class Caret extends Module {
*/ */
const isLastBR = i === rightSiblings.length - 1 && $.isLineBreakTag(node as HTMLElement); const isLastBR = i === rightSiblings.length - 1 && $.isLineBreakTag(node as HTMLElement);
return (isLastBR) || $.isEmpty(node) && !$.isLineBreakTag(node); return isLastBR || ($.isEmpty(node) && !$.isLineBreakTag(node));
}); });
if (nothingAtRight && focusOffset === focusNode.textContent.length) { if (nothingAtRight && focusOffset === focusNode.textContent.length) {
@ -286,9 +286,7 @@ export default class Caret extends Module {
break; break;
case this.positions.END: case this.positions.END:
const contentLength = $.getContentLength(nodeToSet); this.set(nodeToSet as HTMLElement, $.getContentLength(nodeToSet));
this.set(nodeToSet as HTMLElement, contentLength);
break; break;
default: default:
@ -459,19 +457,19 @@ export default class Caret extends Module {
/** /**
* Inserts shadow element after passed element where caret can be placed * Inserts shadow element after passed element where caret can be placed
* *
* @param {Node} element * @param {Element} element - element after which shadow caret should be inserted
*/ */
public createShadow(element): void { public createShadow(element: Element): void {
const shadowCaret = document.createElement('span'); const shadowCaret = document.createElement('span');
shadowCaret.classList.add(Caret.CSS.shadowCaret); shadowCaret.classList.add(Caret.CSS.shadowCaret);
element.insertAdjacentElement('beforeEnd', shadowCaret); element.insertAdjacentElement('beforeend', shadowCaret);
} }
/** /**
* Restores caret position * Restores caret position
* *
* @param {HTMLElement} element * @param {HTMLElement} element - element where caret should be restored
*/ */
public restoreCaret(element: HTMLElement): void { public restoreCaret(element: HTMLElement): void {
const shadowCaret = element.querySelector(`.${Caret.CSS.shadowCaret}`); const shadowCaret = element.querySelector(`.${Caret.CSS.shadowCaret}`);
@ -543,11 +541,13 @@ export default class Caret extends Module {
* <p></p> | right first-level siblings * <p></p> | right first-level siblings
* <p></p> | * <p></p> |
* </div> * </div>
* @returns {Element[]} *
* @param from * @param {HTMLElement} from - element from which siblings should be searched
* @param direction * @param {'left' | 'right'} direction - direction of search
*
* @returns {HTMLElement[]}
*/ */
private getHigherLevelSiblings(from: HTMLElement, direction?: string): HTMLElement[] { private getHigherLevelSiblings(from: HTMLElement, direction?: 'left' | 'right'): HTMLElement[] {
let current = from; let current = from;
const siblings = []; const siblings = [];

View file

@ -27,7 +27,7 @@ export default class CrossBlockSelection extends Module {
return; return;
} }
const { BlockManager, UI, Listeners } = this.Editor; const { BlockManager, Listeners } = this.Editor;
this.firstSelectedBlock = BlockManager.getBlock(event.target as HTMLElement); this.firstSelectedBlock = BlockManager.getBlock(event.target as HTMLElement);
this.lastSelectedBlock = this.firstSelectedBlock; this.lastSelectedBlock = this.firstSelectedBlock;
@ -86,7 +86,7 @@ export default class CrossBlockSelection extends Module {
* *
* @param {Event} reason - event caused clear of selection * @param {Event} reason - event caused clear of selection
*/ */
public clear(reason?: Event) { public clear(reason?: Event): void {
const { BlockManager, BlockSelection, Caret } = this.Editor; const { BlockManager, BlockSelection, Caret } = this.Editor;
const fIndex = BlockManager.blocks.indexOf(this.firstSelectedBlock); const fIndex = BlockManager.blocks.indexOf(this.firstSelectedBlock);
const lIndex = BlockManager.blocks.indexOf(this.lastSelectedBlock); const lIndex = BlockManager.blocks.indexOf(this.lastSelectedBlock);
@ -135,7 +135,7 @@ export default class CrossBlockSelection extends Module {
* Mouse over event handler * Mouse over event handler
* Gets target and related blocks and change selected state for blocks in between * Gets target and related blocks and change selected state for blocks in between
* *
* @param {MouseEvent} event * @param {MouseEvent} event - mouse over event
*/ */
private onMouseOver = (event: MouseEvent): void => { private onMouseOver = (event: MouseEvent): void => {
const { BlockManager } = this.Editor; const { BlockManager } = this.Editor;
@ -176,8 +176,8 @@ export default class CrossBlockSelection extends Module {
/** /**
* Change blocks selection state between passed two blocks. * Change blocks selection state between passed two blocks.
* *
* @param {Block} firstBlock * @param {Block} firstBlock - first block in range
* @param {Block} lastBlock * @param {Block} lastBlock - last block in range
*/ */
private toggleBlocksSelectedState(firstBlock: Block, lastBlock: Block): void { private toggleBlocksSelectedState(firstBlock: Block, lastBlock: Block): void {
const { BlockManager } = this.Editor; const { BlockManager } = this.Editor;

View file

@ -8,15 +8,13 @@ export default class DragNDrop extends Module {
/** /**
* If drag has been started at editor, we save it * If drag has been started at editor, we save it
* *
* @type Boolean * @type {boolean}
* @private * @private
*/ */
private isStartedAtEditor = false; private isStartedAtEditor = false;
/** /**
* Bind events * Bind events
*
* @private
*/ */
public prepare(): void { public prepare(): void {
this.bindEvents(); this.bindEvents();
@ -45,7 +43,7 @@ export default class DragNDrop extends Module {
/** /**
* Handle drop event * Handle drop event
* *
* @param {DragEvent} dropEvent * @param {DragEvent} dropEvent - drop event
*/ */
private processDrop = async (dropEvent: DragEvent): Promise<void> => { private processDrop = async (dropEvent: DragEvent): Promise<void> => {
const { const {

View file

@ -19,7 +19,7 @@ export default class Events extends Module {
* *
* @type {{}} * @type {{}}
*/ */
private subscribers: {[name: string]: Array<(data?: any) => any>} = {}; private subscribers: {[name: string]: Array<(data?: object) => object>} = {};
/** /**
* Subscribe any event on callback * Subscribe any event on callback
@ -27,7 +27,7 @@ export default class Events extends Module {
* @param {string} eventName - event name * @param {string} eventName - event name
* @param {Function} callback - subscriber * @param {Function} callback - subscriber
*/ */
public on(eventName: string, callback: (data: any) => any) { public on(eventName: string, callback: (data: object) => object): void {
if (!(eventName in this.subscribers)) { if (!(eventName in this.subscribers)) {
this.subscribers[eventName] = []; this.subscribers[eventName] = [];
} }
@ -42,12 +42,12 @@ export default class Events extends Module {
* @param {string} eventName - event name * @param {string} eventName - event name
* @param {Function} callback - subscriber * @param {Function} callback - subscriber
*/ */
public once(eventName: string, callback: (data: any) => any) { public once(eventName: string, callback: (data: object) => object): void {
if (!(eventName in this.subscribers)) { if (!(eventName in this.subscribers)) {
this.subscribers[eventName] = []; this.subscribers[eventName] = [];
} }
const wrappedCallback = (data: any) => { const wrappedCallback = (data: object): object => {
const result = callback(data); const result = callback(data);
const indexOfHandler = this.subscribers[eventName].indexOf(wrappedCallback); const indexOfHandler = this.subscribers[eventName].indexOf(wrappedCallback);
@ -69,7 +69,7 @@ export default class Events extends Module {
* @param {string} eventName - event name * @param {string} eventName - event name
* @param {object} data - subscribers get this data when they were fired * @param {object} data - subscribers get this data when they were fired
*/ */
public emit(eventName: string, data?: any): void { public emit(eventName: string, data?: object): void {
if (!this.subscribers[eventName]) { if (!this.subscribers[eventName]) {
return; return;
} }
@ -82,12 +82,12 @@ export default class Events extends Module {
} }
/** /**
* Unsubsribe callback from event * Unsubscribe callback from event
* *
* @param eventName * @param {string} eventName - event name
* @param callback * @param {Function} callback - event handler
*/ */
public off(eventName: string, callback: (data: any) => void): void { public off(eventName: string, callback: (data: object) => object): void {
for (let i = 0; i < this.subscribers[eventName].length; i++) { for (let i = 0; i < this.subscribers[eventName].length; i++) {
if (this.subscribers[eventName][i] === callback) { if (this.subscribers[eventName][i] === callback) {
delete this.subscribers[eventName][i]; delete this.subscribers[eventName][i];

View file

@ -2,6 +2,8 @@ import Module from '../__module';
/** /**
* Event listener information * Event listener information
*
* @interface ListenerData
*/ */
export interface ListenerData { export interface ListenerData {
/** /**
@ -17,7 +19,7 @@ export interface ListenerData {
/** /**
* Event handler * Event handler
* *
* @param {Event} event * @param {Event} event - event object
*/ */
handler: (event: Event) => void; handler: (event: Event) => void;
@ -40,7 +42,7 @@ export interface ListenerData {
/** /**
* @typedef {Listeners} Listeners * @typedef {Listeners} Listeners
* @property {Array} allListeners * @property {ListenerData[]} allListeners - listeners store
*/ */
export default class Listeners extends Module { export default class Listeners extends Module {
/** /**
@ -109,9 +111,12 @@ export default class Listeners extends Module {
} }
/** /**
* @param {EventTarget} element * Finds and returns first listener by passed params
* @param {string} eventType *
* @param {Function} handler * @param {EventTarget} element - event target
* @param {string} [eventType] - event type
* @param {Function} [handler] - event handler
*
* @returns {ListenerData|null} * @returns {ListenerData|null}
*/ */
public findOne(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData { public findOne(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData {
@ -121,9 +126,12 @@ export default class Listeners extends Module {
} }
/** /**
* @param {EventTarget} element * Return all stored listeners by passed params
* @param {string} eventType *
* @param {Function} handler * @param {EventTarget} element - event target
* @param {string} eventType - event type
* @param {Function} handler - event handler
*
* @returns {ListenerData[]} * @returns {ListenerData[]}
*/ */
public findAll(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData[] { public findAll(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData[] {
@ -156,6 +164,7 @@ export default class Listeners extends Module {
* Search method: looks for listener by passed element * Search method: looks for listener by passed element
* *
* @param {EventTarget} element - searching element * @param {EventTarget} element - searching element
*
* @returns {Array} listeners that found on element * @returns {Array} listeners that found on element
*/ */
private findByEventTarget(element: EventTarget): ListenerData[] { private findByEventTarget(element: EventTarget): ListenerData[] {
@ -169,8 +178,9 @@ export default class Listeners extends Module {
/** /**
* Search method: looks for listener by passed event type * Search method: looks for listener by passed event type
* *
* @param {string} eventType * @param {string} eventType - event type
* @returns {Array} listeners that found on element *
* @returns {ListenerData[]} listeners that found on element
*/ */
private findByType(eventType: string): ListenerData[] { private findByType(eventType: string): ListenerData[] {
return this.allListeners.filter((listener) => { return this.allListeners.filter((listener) => {
@ -183,8 +193,9 @@ export default class Listeners extends Module {
/** /**
* Search method: looks for listener by passed handler * Search method: looks for listener by passed handler
* *
* @param {Function} handler * @param {Function} handler - event handler
* @returns {Array} listeners that found on element *
* @returns {ListenerData[]} listeners that found on element
*/ */
private findByHandler(handler: (event: Event) => void): ListenerData[] { private findByHandler(handler: (event: Event) => void): ListenerData[] {
return this.allListeners.filter((listener) => { return this.allListeners.filter((listener) => {

View file

@ -49,7 +49,7 @@ export default class ModificationsObserver extends Module {
/** /**
* Clear timeout and set null to mutationDebouncer property * Clear timeout and set null to mutationDebouncer property
*/ */
public destroy() { public destroy(): void {
this.mutationDebouncer = null; this.mutationDebouncer = null;
if (this.observer) { if (this.observer) {
this.observer.disconnect(); this.observer.disconnect();
@ -76,7 +76,7 @@ export default class ModificationsObserver extends Module {
* Allows to disable observer, * Allows to disable observer,
* for example when Editor wants to stealthy mutate DOM * for example when Editor wants to stealthy mutate DOM
*/ */
public disable() { public disable(): void {
this.disabled = true; this.disabled = true;
} }
@ -84,7 +84,7 @@ export default class ModificationsObserver extends Module {
* Enables mutation handling * Enables mutation handling
* Should be called after .disable() * Should be called after .disable()
*/ */
public enable() { public enable(): void {
this.disabled = false; this.disabled = false;
} }
@ -113,10 +113,10 @@ export default class ModificationsObserver extends Module {
/** /**
* MutationObserver events handler * MutationObserver events handler
* *
* @param mutationList * @param {MutationRecord[]} mutationList - list of mutations
* @param observer * @param {MutationObserver} observer - observer instance
*/ */
private mutationHandler(mutationList, observer) { private mutationHandler(mutationList: MutationRecord[], observer): void {
/** /**
* Skip mutations in stealth mode * Skip mutations in stealth mode
*/ */
@ -134,18 +134,14 @@ export default class ModificationsObserver extends Module {
mutationList.forEach((mutation) => { mutationList.forEach((mutation) => {
switch (mutation.type) { switch (mutation.type) {
case 'childList': case 'childList':
case 'subtree':
case 'characterData': case 'characterData':
case 'characterDataOldValue':
contentMutated = true; contentMutated = true;
break; break;
case 'attributes': case 'attributes':
const mutatedTarget = mutation.target as Element;
/** /**
* Changes on Element.ce-block usually is functional * Changes on Element.ce-block usually is functional
*/ */
if (!mutatedTarget.classList.contains(Block.CSS.wrapper)) { if (!(mutation.target as Element).classList.contains(Block.CSS.wrapper)) {
contentMutated = true; contentMutated = true;
} }
break; break;

View file

@ -14,9 +14,9 @@ export default class Notifier extends Module {
/** /**
* Show web notification * Show web notification
* *
* @param {NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions} options * @param {NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions} options - notification options
*/ */
public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions) { public show(options: NotifierOptions | ConfirmNotifierOptions | PromptNotifierOptions): void {
notifier.show(options); notifier.show(options);
} }
} }

View file

@ -70,6 +70,8 @@ interface FilesSubstitution {
/** /**
* Processed paste data object. * Processed paste data object.
*
* @interface PasteData
*/ */
interface PasteData { interface PasteData {
/** /**
@ -151,7 +153,7 @@ export default class Paste extends Module {
* Handle pasted or dropped data transfer object * Handle pasted or dropped data transfer object
* *
* @param {DataTransfer} dataTransfer - pasted or dropped data transfer object * @param {DataTransfer} dataTransfer - pasted or dropped data transfer object
* @param {boolean} isDragNDrop * @param {boolean} isDragNDrop - true if data transfer comes from drag'n'drop events
*/ */
public async processDataTransfer(dataTransfer: DataTransfer, isDragNDrop = false): Promise<void> { public async processDataTransfer(dataTransfer: DataTransfer, isDragNDrop = false): Promise<void> {
const { Sanitizer } = this.Editor; const { Sanitizer } = this.Editor;
@ -161,6 +163,7 @@ export default class Paste extends Module {
/** /**
* In Microsoft Edge types is DOMStringList. So 'contains' is used to check if 'Files' type included * In Microsoft Edge types is DOMStringList. So 'contains' is used to check if 'Files' type included
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const includesFiles = types.includes ? types.includes('Files') : (types as any).contains('Files'); const includesFiles = types.includes ? types.includes('Files') : (types as any).contains('Files');
if (includesFiles) { if (includesFiles) {
@ -216,7 +219,7 @@ export default class Paste extends Module {
* @param {string} data - text to process. Can be HTML or plain. * @param {string} data - text to process. Can be HTML or plain.
* @param {boolean} isHTML - if passed string is HTML, this parameter should be true * @param {boolean} isHTML - if passed string is HTML, this parameter should be true
*/ */
public async processText(data: string, isHTML = false) { public async processText(data: string, isHTML = false): Promise<void> {
const { Caret, BlockManager, Tools } = this.Editor; const { Caret, BlockManager, Tools } = this.Editor;
const dataToInsert = isHTML ? this.processHTML(data) : this.processPlain(data); const dataToInsert = isHTML ? this.processHTML(data) : this.processPlain(data);
@ -266,9 +269,6 @@ export default class Paste extends Module {
/** /**
* Process paste config for each tool * Process paste config for each tool
*
* @param {string} name
* @param {Tool} tool
*/ */
private processTool = ([name, tool]: [string, BlockToolConstructable]): void => { private processTool = ([name, tool]: [string, BlockToolConstructable]): void => {
try { try {
@ -312,7 +312,7 @@ export default class Paste extends Module {
const tags = toolPasteConfig.tags || []; const tags = toolPasteConfig.tags || [];
tags.forEach((tag) => { tags.forEach((tag) => {
if (this.toolsTags.hasOwnProperty(tag)) { if (Object.prototype.hasOwnProperty.call(this.toolsTags, tag)) {
_.log( _.log(
`Paste handler for «${name}» Tool on «${tag}» tag is skipped ` + `Paste handler for «${name}» Tool on «${tag}» tag is skipped ` +
`because it is already used by «${this.toolsTags[tag].tool}» Tool.`, `because it is already used by «${this.toolsTags[tag].tool}» Tool.`,
@ -404,6 +404,7 @@ export default class Paste extends Module {
* Check if browser behavior suits better * Check if browser behavior suits better
* *
* @param {EventTarget} element - element where content has been pasted * @param {EventTarget} element - element where content has been pasted
*
* @returns {boolean} * @returns {boolean}
*/ */
private isNativeBehaviour(element: EventTarget): boolean { private isNativeBehaviour(element: EventTarget): boolean {
@ -413,14 +414,14 @@ export default class Paste extends Module {
/** /**
* Check if Editor should process pasted data and pass data transfer object to handler * Check if Editor should process pasted data and pass data transfer object to handler
* *
* @param {ClipboardEvent} event * @param {ClipboardEvent} event - clipboard event
*/ */
private handlePasteEvent = async (event: ClipboardEvent): Promise<void> => { private handlePasteEvent = async (event: ClipboardEvent): Promise<void> => {
const { BlockManager, Toolbar } = this.Editor; const { BlockManager, Toolbar } = this.Editor;
/** If target is native input or is not Block, use browser behaviour */ /** If target is native input or is not Block, use browser behaviour */
if ( if (
!BlockManager.currentBlock || this.isNativeBehaviour(event.target) && !event.clipboardData.types.includes('Files') !BlockManager.currentBlock || (this.isNativeBehaviour(event.target) && !event.clipboardData.types.includes('Files'))
) { ) {
return; return;
} }
@ -444,7 +445,7 @@ export default class Paste extends Module {
* *
* @param {FileList} items - pasted or dropped items * @param {FileList} items - pasted or dropped items
*/ */
private async processFiles(items: FileList) { private async processFiles(items: FileList): Promise<void> {
const { BlockManager, Tools } = this.Editor; const { BlockManager, Tools } = this.Editor;
let dataToInsert: Array<{type: string; event: PasteEvent}>; let dataToInsert: Array<{type: string; event: PasteEvent}>;
@ -469,9 +470,9 @@ export default class Paste extends Module {
/** /**
* Get information about file and find Tool to handle it * Get information about file and find Tool to handle it
* *
* @param {File} file * @param {File} file - file to process
*/ */
private async processFile(file: File) { private async processFile(file: File): Promise<{event: PasteEvent; type: string}> {
const extension = _.getFileExtension(file); const extension = _.getFileExtension(file);
const foundConfig = Object const foundConfig = Object
@ -507,7 +508,8 @@ export default class Paste extends Module {
/** /**
* Split HTML string to blocks and return it as array of Block data * Split HTML string to blocks and return it as array of Block data
* *
* @param {string} innerHTML * @param {string} innerHTML - html string to process
*
* @returns {PasteData[]} * @returns {PasteData[]}
*/ */
private processHTML(innerHTML: string): PasteData[] { private processHTML(innerHTML: string): PasteData[] {
@ -569,12 +571,12 @@ export default class Paste extends Module {
/** /**
* Split plain text by new line symbols and return it as array of Block data * Split plain text by new line symbols and return it as array of Block data
* *
* @param {string} plain * @param {string} plain - string to process
*
* @returns {PasteData[]} * @returns {PasteData[]}
*/ */
private processPlain(plain: string): PasteData[] { private processPlain(plain: string): PasteData[] {
const { initialBlock } = this.config as {initialBlock: string}, const { initialBlock } = this.config as {initialBlock: string};
{ Tools } = this.Editor;
if (!plain) { if (!plain) {
return []; return [];
@ -606,7 +608,7 @@ export default class Paste extends Module {
/** /**
* Process paste of single Block tool content * Process paste of single Block tool content
* *
* @param {PasteData} dataToInsert * @param {PasteData} dataToInsert - data of Block to inseret
*/ */
private async processSingleBlock(dataToInsert: PasteData): Promise<void> { private async processSingleBlock(dataToInsert: PasteData): Promise<void> {
const { Caret, BlockManager, Tools } = this.Editor; const { Caret, BlockManager, Tools } = this.Editor;
@ -634,11 +636,11 @@ export default class Paste extends Module {
* 2. Insert new block if it is not the same type as current one * 2. Insert new block if it is not the same type as current one
* 3. Just insert text if there is no substitutions * 3. Just insert text if there is no substitutions
* *
* @param {PasteData} dataToInsert * @param {PasteData} dataToInsert - data of Block to insert
*/ */
private async processInlinePaste(dataToInsert: PasteData): Promise<void> { private async processInlinePaste(dataToInsert: PasteData): Promise<void> {
const { BlockManager, Caret, Sanitizer, Tools } = this.Editor; const { BlockManager, Caret, Sanitizer, Tools } = this.Editor;
const { content, tool } = dataToInsert; const { content } = dataToInsert;
const currentBlockIsInitial = BlockManager.currentBlock && Tools.isInitial(BlockManager.currentBlock.tool); const currentBlockIsInitial = BlockManager.currentBlock && Tools.isInitial(BlockManager.currentBlock.tool);
@ -675,8 +677,9 @@ export default class Paste extends Module {
/** /**
* Get patterns` matches * Get patterns` matches
* *
* @param {string} text * @param {string} text - text to process
* @returns Promise<{data: BlockToolData, tool: string}> *
* @returns {Promise<{event: PasteEvent, tool: string}>}
*/ */
private async processPattern(text: string): Promise<{event: PasteEvent; tool: string}> { private async processPattern(text: string): Promise<{event: PasteEvent; tool: string}> {
const pattern = this.toolsPatterns.find((substitute) => { const pattern = this.toolsPatterns.find((substitute) => {
@ -707,8 +710,9 @@ export default class Paste extends Module {
/** /**
* Insert pasted Block content to Editor * Insert pasted Block content to Editor
* *
* @param {PasteData} data * @param {PasteData} data - data to insert
* @param {boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block * @param {boolean} canReplaceCurrentBlock - if true and is current Block is empty, will replace current Block
*
* @returns {void} * @returns {void}
*/ */
private insertBlock(data: PasteData, canReplaceCurrentBlock = false): void { private insertBlock(data: PasteData, canReplaceCurrentBlock = false): void {
@ -757,17 +761,62 @@ export default class Paste extends Module {
}); });
} }
/**
* Fetch nodes from Element node
*
* @param {Node} node - current node
* @param {Node[]} nodes - processed nodes
* @param {Node} destNode - destination node
*
* @returns {Node[]}
*/
private processElementNode(node: Node, nodes: Node[], destNode: Node): Node[] | void {
const tags = Object.keys(this.toolsTags);
const element = node as HTMLElement;
const { tool = '' } = this.toolsTags[element.tagName] || {};
const toolTags = this.tagsByTool[tool] || [];
const isSubstitutable = tags.includes(element.tagName);
const isBlockElement = $.blockElements.includes(element.tagName.toLowerCase());
const containsAnotherToolTags = Array
.from(element.children)
.some(
({ tagName }) => tags.includes(tagName) && !toolTags.includes(tagName)
);
const containsBlockElements = Array.from(element.children).some(
({ tagName }) => $.blockElements.includes(tagName.toLowerCase())
);
/** Append inline elements to previous fragment */
if (!isBlockElement && !isSubstitutable && !containsAnotherToolTags) {
destNode.appendChild(element);
return [...nodes, destNode];
}
if (
(isSubstitutable && !containsAnotherToolTags) ||
(isBlockElement && !containsBlockElements && !containsAnotherToolTags)
) {
return [...nodes, destNode, element];
}
}
/** /**
* Recursively divide HTML string to two types of nodes: * Recursively divide HTML string to two types of nodes:
* 1. Block element * 1. Block element
* 2. Document Fragments contained text and markup tags like a, b, i etc. * 2. Document Fragments contained text and markup tags like a, b, i etc.
* *
* @param {Node} wrapper * @param {Node} wrapper - wrapper of paster HTML content
*
* @returns {Node[]} * @returns {Node[]}
*/ */
private getNodes(wrapper: Node): Node[] { private getNodes(wrapper: Node): Node[] {
const children = Array.from(wrapper.childNodes), const children = Array.from(wrapper.childNodes);
tags = Object.keys(this.toolsTags); let elementNodeProcessingResult: Node[] | void;
const reducer = (nodes: Node[], node: Node): Node[] => { const reducer = (nodes: Node[], node: Node): Node[] => {
if ($.isEmpty(node) && !$.isSingleTag(node as HTMLElement)) { if ($.isEmpty(node) && !$.isSingleTag(node as HTMLElement)) {
@ -789,35 +838,10 @@ export default class Paste extends Module {
* 2. Check if it contains another block or substitutable elements * 2. Check if it contains another block or substitutable elements
*/ */
case Node.ELEMENT_NODE: case Node.ELEMENT_NODE:
const element = node as HTMLElement; elementNodeProcessingResult = this.processElementNode(node, nodes, destNode);
const { tool = '' } = this.toolsTags[element.tagName] || {}; if (elementNodeProcessingResult) {
const toolTags = this.tagsByTool[tool] || []; return elementNodeProcessingResult;
const isSubstitutable = tags.includes(element.tagName);
const isBlockElement = $.blockElements.includes(element.tagName.toLowerCase());
const containsAnotherToolTags = Array
.from(element.children)
.some(
({ tagName }) => tags.includes(tagName) && !toolTags.includes(tagName)
);
const containsBlockElements = Array.from(element.children).some(
({ tagName }) => $.blockElements.includes(tagName.toLowerCase())
);
/** Append inline elements to previous fragment */
if (!isBlockElement && !isSubstitutable && !containsAnotherToolTags) {
destNode.appendChild(element);
return [...nodes, destNode];
}
if (
(isSubstitutable && !containsAnotherToolTags) ||
(isBlockElement && !containsBlockElements && !containsAnotherToolTags)
) {
return [...nodes, destNode, element];
} }
break; break;
@ -842,8 +866,8 @@ export default class Paste extends Module {
/** /**
* Compose paste event with passed type and detail * Compose paste event with passed type and detail
* *
* @param {string} type * @param {string} type - event type
* @param {PasteEventDetail} detail * @param {PasteEventDetail} detail - event detail
*/ */
private composePasteEvent(type: string, detail: PasteEventDetail): PasteEvent { private composePasteEvent(type: string, detail: PasteEventDetail): PasteEvent {
return new CustomEvent(type, { return new CustomEvent(type, {

View file

@ -20,7 +20,7 @@ export default class RectangleSelection extends Module {
* *
* @returns {{wrapper: string, content: string}} * @returns {{wrapper: string, content: string}}
*/ */
static get CSS() { public static get CSS(): {[name: string]: string} {
return { return {
overlay: 'codex-editor-overlay', overlay: 'codex-editor-overlay',
overlayContainer: 'codex-editor-overlay__container', overlayContainer: 'codex-editor-overlay__container',
@ -136,7 +136,7 @@ export default class RectangleSelection extends Module {
* @param {number} pageX - X coord of mouse * @param {number} pageX - X coord of mouse
* @param {number} pageY - Y coord of mouse * @param {number} pageY - Y coord of mouse
*/ */
public startSelection(pageX, pageY) { public startSelection(pageX, pageY): void {
const elemWhereSelectionStart = document.elementFromPoint(pageX - window.pageXOffset, pageY - window.pageYOffset); const elemWhereSelectionStart = document.elementFromPoint(pageX - window.pageXOffset, pageY - window.pageYOffset);
/** /**
@ -175,7 +175,7 @@ export default class RectangleSelection extends Module {
/** /**
* Clear all params to end selection * Clear all params to end selection
*/ */
public endSelection() { public endSelection(): void {
this.mousedown = false; this.mousedown = false;
this.startX = 0; this.startX = 0;
this.startY = 0; this.startY = 0;
@ -185,14 +185,14 @@ export default class RectangleSelection extends Module {
/** /**
* is RectSelection Activated * is RectSelection Activated
*/ */
public isRectActivated() { public isRectActivated(): boolean {
return this.isRectSelectionActivated; return this.isRectSelectionActivated;
} }
/** /**
* Mark that selection is end * Mark that selection is end
*/ */
public clearSelection() { public clearSelection(): void {
this.isRectSelectionActivated = false; this.isRectSelectionActivated = false;
} }
@ -201,7 +201,7 @@ export default class RectangleSelection extends Module {
* *
* @param {number} clientY - Y coord of mouse * @param {number} clientY - Y coord of mouse
*/ */
private scrollByZones(clientY) { private scrollByZones(clientY): void {
this.inScrollZone = null; this.inScrollZone = null;
if (clientY <= this.HEIGHT_OF_SCROLL_ZONE) { if (clientY <= this.HEIGHT_OF_SCROLL_ZONE) {
this.inScrollZone = this.TOP_SCROLL_ZONE; this.inScrollZone = this.TOP_SCROLL_ZONE;
@ -223,9 +223,11 @@ export default class RectangleSelection extends Module {
} }
/** /**
* Generates required HTML elements
* *
* @returns {object<string, Element>}
*/ */
private genHTML() { private genHTML(): {container: Element; overlay: Element} {
const { UI } = this.Editor; const { UI } = this.Editor;
const container = UI.nodes.holder.querySelector('.' + UI.CSS.editorWrapper); const container = UI.nodes.holder.querySelector('.' + UI.CSS.editorWrapper);
@ -250,7 +252,7 @@ export default class RectangleSelection extends Module {
* *
* @param {number} speed - speed of scrolling * @param {number} speed - speed of scrolling
*/ */
private scrollVertical(speed) { private scrollVertical(speed): void {
if (!(this.inScrollZone && this.mousedown)) { if (!(this.inScrollZone && this.mousedown)) {
return; return;
} }
@ -266,9 +268,9 @@ export default class RectangleSelection extends Module {
/** /**
* Handles the change in the rectangle and its effect * Handles the change in the rectangle and its effect
* *
* @param {MouseEvent} event * @param {MouseEvent} event - mouse event
*/ */
private changingRectangle(event) { private changingRectangle(event): void {
if (!this.mousedown) { if (!this.mousedown) {
return; return;
} }
@ -310,7 +312,7 @@ export default class RectangleSelection extends Module {
/** /**
* Shrink rect to singular point * Shrink rect to singular point
*/ */
private shrinkRectangleToPoint() { private shrinkRectangleToPoint(): void {
this.overlayRectangle.style.left = `${this.startX - window.pageXOffset}px`; this.overlayRectangle.style.left = `${this.startX - window.pageXOffset}px`;
this.overlayRectangle.style.top = `${this.startY - window.pageYOffset}px`; this.overlayRectangle.style.top = `${this.startY - window.pageYOffset}px`;
this.overlayRectangle.style.bottom = `calc(100% - ${this.startY - window.pageYOffset}px`; this.overlayRectangle.style.bottom = `calc(100% - ${this.startY - window.pageYOffset}px`;
@ -320,17 +322,17 @@ export default class RectangleSelection extends Module {
/** /**
* Select or unselect all of blocks in array if rect is out or in selectable area * Select or unselect all of blocks in array if rect is out or in selectable area
*/ */
private inverseSelection() { private inverseSelection(): void {
const firstBlockInStack = this.Editor.BlockManager.getBlockByIndex(this.stackOfSelected[0]); const firstBlockInStack = this.Editor.BlockManager.getBlockByIndex(this.stackOfSelected[0]);
const isSelecteMode = firstBlockInStack.selected; const isSelectedMode = firstBlockInStack.selected;
if (this.rectCrossesBlocks && !isSelecteMode) { if (this.rectCrossesBlocks && !isSelectedMode) {
for (const it of this.stackOfSelected) { for (const it of this.stackOfSelected) {
this.Editor.BlockSelection.selectBlockByIndex(it); this.Editor.BlockSelection.selectBlockByIndex(it);
} }
} }
if (!this.rectCrossesBlocks && isSelecteMode) { if (!this.rectCrossesBlocks && isSelectedMode) {
for (const it of this.stackOfSelected) { for (const it of this.stackOfSelected) {
this.Editor.BlockSelection.unSelectBlockByIndex(it); this.Editor.BlockSelection.unSelectBlockByIndex(it);
} }
@ -340,7 +342,7 @@ export default class RectangleSelection extends Module {
/** /**
* Updates size of rectangle * Updates size of rectangle
*/ */
private updateRectangleSize() { private updateRectangleSize(): void {
// Depending on the position of the mouse relative to the starting point, // Depending on the position of the mouse relative to the starting point,
// change this.e distance from the desired edge of the screen*/ // change this.e distance from the desired edge of the screen*/
if (this.mouseY >= this.startY) { if (this.mouseY >= this.startY) {
@ -363,9 +365,9 @@ export default class RectangleSelection extends Module {
/** /**
* Collects information needed to determine the behavior of the rectangle * Collects information needed to determine the behavior of the rectangle
* *
* @returns {number} index - index next Block, leftPos - start of left border of Block, rightPos - right border * @returns {object} index - index next Block, leftPos - start of left border of Block, rightPos - right border
*/ */
private genInfoForMouseSelection() { private genInfoForMouseSelection(): {index: number; leftPos: number; rightPos: number} {
const widthOfRedactor = document.body.offsetWidth; const widthOfRedactor = document.body.offsetWidth;
const centerOfRedactor = widthOfRedactor / 2; const centerOfRedactor = widthOfRedactor / 2;
const Y = this.mouseY - window.pageYOffset; const Y = this.mouseY - window.pageYOffset;
@ -393,7 +395,7 @@ export default class RectangleSelection extends Module {
* *
* @param index - index of block in redactor * @param index - index of block in redactor
*/ */
private addBlockInSelection(index) { private addBlockInSelection(index): void {
if (this.rectCrossesBlocks) { if (this.rectCrossesBlocks) {
this.Editor.BlockSelection.selectBlockByIndex(index); this.Editor.BlockSelection.selectBlockByIndex(index);
} }
@ -405,7 +407,7 @@ export default class RectangleSelection extends Module {
* *
* @param {object} index - index of new block in the reactor * @param {object} index - index of new block in the reactor
*/ */
private trySelectNextBlock(index) { private trySelectNextBlock(index): void {
const sameBlock = this.stackOfSelected[this.stackOfSelected.length - 1] === index; const sameBlock = this.stackOfSelected[this.stackOfSelected.length - 1] === index;
const sizeStack = this.stackOfSelected.length; const sizeStack = this.stackOfSelected.length;
const down = 1, up = -1, undef = 0; const down = 1, up = -1, undef = 0;
@ -415,10 +417,16 @@ export default class RectangleSelection extends Module {
} }
const blockNumbersIncrease = this.stackOfSelected[sizeStack - 1] - this.stackOfSelected[sizeStack - 2] > 0; const blockNumbersIncrease = this.stackOfSelected[sizeStack - 1] - this.stackOfSelected[sizeStack - 2] > 0;
const direction = sizeStack <= 1 ? undef : blockNumbersIncrease ? down : up;
const selectionInDownDurection = index > this.stackOfSelected[sizeStack - 1] && direction === down; let direction = undef;
if (sizeStack > 1) {
direction = blockNumbersIncrease ? down : up;
}
const selectionInDownDirection = index > this.stackOfSelected[sizeStack - 1] && direction === down;
const selectionInUpDirection = index < this.stackOfSelected[sizeStack - 1] && direction === up; const selectionInUpDirection = index < this.stackOfSelected[sizeStack - 1] && direction === up;
const generalSelection = selectionInDownDurection || selectionInUpDirection || direction === undef; const generalSelection = selectionInDownDirection || selectionInUpDirection || direction === undef;
const reduction = !generalSelection; const reduction = !generalSelection;
// When the selection is too fast, some blocks do not have time to be noticed. Fix it. // When the selection is too fast, some blocks do not have time to be noticed. Fix it.
@ -451,9 +459,9 @@ export default class RectangleSelection extends Module {
// cmp for different directions // cmp for different directions
if (index > this.stackOfSelected[sizeStack - 1]) { if (index > this.stackOfSelected[sizeStack - 1]) {
cmp = () => index > this.stackOfSelected[i]; cmp = (): boolean => index > this.stackOfSelected[i];
} else { } else {
cmp = () => index < this.stackOfSelected[i]; cmp = (): boolean => index < this.stackOfSelected[i];
} }
// Remove blocks missed due to speed. // Remove blocks missed due to speed.

View file

@ -43,10 +43,10 @@ export default class Renderer extends Module {
/** /**
* Make plugin blocks from array of plugin`s data * Make plugin blocks from array of plugin`s data
* *
* @param {RendererBlocks[]} blocks * @param {BlockToolData[]} blocks - blocks to render
*/ */
public async render(blocks: BlockToolData[]): Promise<void> { public async render(blocks: BlockToolData[]): Promise<void> {
const chainData = blocks.map((block) => ({ function: () => this.insertBlock(block) })); const chainData = blocks.map((block) => ({ function: (): Promise<void> => this.insertBlock(block) }));
const sequence = await _.sequence(chainData as ChainData[]); const sequence = await _.sequence(chainData as ChainData[]);
@ -60,9 +60,8 @@ export default class Renderer extends Module {
* Add plugin instance to BlockManager * Add plugin instance to BlockManager
* Insert block to working zone * Insert block to working zone
* *
* @param {object} item * @param {object} item - Block data to insert
* @returns {Promise<void>} * @returns {Promise<void>}
* @private
*/ */
public async insertBlock(item): Promise<void> { public async insertBlock(item): Promise<void> {
const { Tools, BlockManager } = this.Editor; const { Tools, BlockManager } = this.Editor;

View file

@ -57,8 +57,7 @@ export default class Sanitizer extends Module {
* *
* Enumerate blocks and clean data * Enumerate blocks and clean data
* *
* @param blocksData * @param {Array<{tool, data: BlockToolData}>} blocksData - blocks' data to sanitize
* @param {{tool, data: BlockToolData}[]} blocksData[]
*/ */
public sanitizeBlocks( public sanitizeBlocks(
blocksData: Array<{tool: string; data: BlockToolData}> blocksData: Array<{tool: string; data: BlockToolData}>
@ -70,7 +69,7 @@ export default class Sanitizer extends Module {
return block; return block;
} }
block.data = this.deepSanitize(block.data, toolConfig); block.data = this.deepSanitize(block.data, toolConfig) as BlockToolData;
return block; return block;
}); });
@ -82,7 +81,7 @@ export default class Sanitizer extends Module {
* @param {BlockToolData|object|*} dataToSanitize - taint string or object/array that contains taint string * @param {BlockToolData|object|*} dataToSanitize - taint string or object/array that contains taint string
* @param {SanitizerConfig} rules - object with sanitizer rules * @param {SanitizerConfig} rules - object with sanitizer rules
*/ */
public deepSanitize(dataToSanitize: any, rules: SanitizerConfig): any { public deepSanitize(dataToSanitize: object | string, rules: SanitizerConfig): object | string {
/** /**
* BlockData It may contain 3 types: * BlockData It may contain 3 types:
* - Array * - Array
@ -138,8 +137,8 @@ export default class Sanitizer extends Module {
/** /**
* Merge with inline tool config * Merge with inline tool config
* *
* @param {string} toolName * @param {string} toolName - tool name
* @param {SanitizerConfig} toolRules *
* @returns {SanitizerConfig} * @returns {SanitizerConfig}
*/ */
public composeToolConfig(toolName: string): SanitizerConfig { public composeToolConfig(toolName: string): SanitizerConfig {
@ -166,7 +165,7 @@ export default class Sanitizer extends Module {
const toolConfig = {} as SanitizerConfig; const toolConfig = {} as SanitizerConfig;
for (const fieldName in toolRules) { for (const fieldName in toolRules) {
if (toolRules.hasOwnProperty(fieldName)) { if (Object.prototype.hasOwnProperty.call(toolRules, fieldName)) {
const rule = toolRules[fieldName]; const rule = toolRules[fieldName];
if (typeof rule === 'object') { if (typeof rule === 'object') {
@ -186,7 +185,7 @@ export default class Sanitizer extends Module {
* When Tool's "inlineToolbar" value is True, get all sanitizer rules from all tools, * When Tool's "inlineToolbar" value is True, get all sanitizer rules from all tools,
* otherwise get only enabled * otherwise get only enabled
* *
* @param name * @param {string} name - Inline Tool name
*/ */
public getInlineToolsConfig(name: string): SanitizerConfig { public getInlineToolsConfig(name: string): SanitizerConfig {
const { Tools } = this.Editor; const { Tools } = this.Editor;
@ -234,7 +233,7 @@ export default class Sanitizer extends Module {
const config: SanitizerConfig = {} as SanitizerConfig; const config: SanitizerConfig = {} as SanitizerConfig;
Object.entries(Tools.inline) Object.entries(Tools.inline)
.forEach(([name, inlineTool]: [string, InlineToolConstructable]) => { .forEach(([, inlineTool]: [string, InlineToolConstructable]) => {
Object.assign(config, inlineTool[Tools.INTERNAL_SETTINGS.SANITIZE_CONFIG]); Object.assign(config, inlineTool[Tools.INTERNAL_SETTINGS.SANITIZE_CONFIG]);
}); });
@ -247,9 +246,9 @@ export default class Sanitizer extends Module {
* Clean array * Clean array
* *
* @param {Array} array - [1, 2, {}, []] * @param {Array} array - [1, 2, {}, []]
* @param {object} ruleForItem * @param {SanitizerConfig} ruleForItem - sanitizer config for array
*/ */
private cleanArray(array: any[], ruleForItem: SanitizerConfig): any[] { private cleanArray(array: Array<object | string>, ruleForItem: SanitizerConfig): Array<object | string> {
return array.map((arrayItem) => this.deepSanitize(arrayItem, ruleForItem)); return array.map((arrayItem) => this.deepSanitize(arrayItem, ruleForItem));
} }
@ -260,11 +259,11 @@ export default class Sanitizer extends Module {
* @param {object} rules - { b: true } or true|false * @param {object} rules - { b: true } or true|false
* @returns {object} * @returns {object}
*/ */
private cleanObject(object: any, rules: SanitizerConfig|{[field: string]: SanitizerConfig}): any { private cleanObject(object: object, rules: SanitizerConfig|{[field: string]: SanitizerConfig}): object {
const cleanData = {}; const cleanData = {};
for (const fieldName in object) { for (const fieldName in object) {
if (!object.hasOwnProperty(fieldName)) { if (!Object.prototype.hasOwnProperty.call(object, fieldName)) {
continue; continue;
} }
@ -284,8 +283,11 @@ export default class Sanitizer extends Module {
} }
/** /**
* @param {string} taintString * Clean primitive value
* @param {SanitizerConfig|boolean} rule *
* @param {string} taintString - string to clean
* @param {SanitizerConfig|boolean} rule - sanitizer rule
*
* @returns {string} * @returns {string}
*/ */
private cleanOneItem(taintString: string, rule: SanitizerConfig|boolean): string { private cleanOneItem(taintString: string, rule: SanitizerConfig|boolean): string {
@ -303,7 +305,7 @@ export default class Sanitizer extends Module {
* { a : true }, {}, false, true, function(){} correct rules * { a : true }, {}, false, true, function(){} correct rules
* undefined, null, 0, 1, 2 not a rules * undefined, null, 0, 1, 2 not a rules
* *
* @param config * @param {SanitizerConfig} config - config to check
*/ */
private isRule(config: SanitizerConfig): boolean { private isRule(config: SanitizerConfig): boolean {
return typeof config === 'object' || typeof config === 'boolean' || typeof config === 'function'; return typeof config === 'object' || typeof config === 'boolean' || typeof config === 'function';
@ -314,8 +316,9 @@ export default class Sanitizer extends Module {
* Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere
* At least, if there is no config overrides, that API uses Default configuration * At least, if there is no config overrides, that API uses Default configuration
* *
* @uses https://www.npmjs.com/package/html-janitor * @see {@link https://www.npmjs.com/package/html-janitor}
* @license https://github.com/guardian/html-janitor/blob/master/LICENSE * @license Apache-2.0
* @see {@link https://github.com/guardian/html-janitor/blob/master/LICENSE}
* *
* @param {SanitizerConfig} config - sanitizer extension * @param {SanitizerConfig} config - sanitizer extension
*/ */

View file

@ -67,7 +67,7 @@ export default class Saver extends Module {
/** /**
* Creates output object with saved data, time and version of editor * Creates output object with saved data, time and version of editor
* *
* @param {ValidatedData} allExtractedData * @param {ValidatedData} allExtractedData - data extracted from Blocks
* @returns {OutputData} * @returns {OutputData}
*/ */
private makeOutput(allExtractedData): OutputData { private makeOutput(allExtractedData): OutputData {

View file

@ -10,6 +10,8 @@ import Module from '../__module';
* Each shortcut must have name and handler * Each shortcut must have name and handler
* `name` is a shortcut, like 'CMD+K', 'CMD+B' etc * `name` is a shortcut, like 'CMD+K', 'CMD+B' etc
* `handler` is a callback * `handler` is a callback
*
* @interface ShortcutData
*/ */
export interface ShortcutData { export interface ShortcutData {
@ -42,7 +44,7 @@ export default class Shortcuts extends Module {
/** /**
* Register shortcut * Register shortcut
* *
* @param {ShortcutData} shortcut * @param {ShortcutData} shortcut - shortcut options
*/ */
public add(shortcut: ShortcutData): void { public add(shortcut: ShortcutData): void {
const newShortcut = new Shortcut({ const newShortcut = new Shortcut({
@ -57,7 +59,7 @@ export default class Shortcuts extends Module {
/** /**
* Remove shortcut * Remove shortcut
* *
* @param {ShortcutData} shortcut * @param {string} shortcut - shortcut name
*/ */
public remove(shortcut: string): void { public remove(shortcut: string): void {
const index = this.registeredShortcuts.findIndex((shc) => shc.name === shortcut); const index = this.registeredShortcuts.findIndex((shc) => shc.name === shortcut);

View file

@ -32,7 +32,7 @@ export default class BlockSettings extends Module {
* *
* @returns {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}} * @returns {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}
*/ */
public get CSS() { public get CSS(): {[name: string]: string} {
return { return {
// Settings Panel // Settings Panel
wrapper: 'ce-settings', wrapper: 'ce-settings',
@ -81,8 +81,6 @@ export default class BlockSettings extends Module {
* Panel with block settings with 2 sections: * Panel with block settings with 2 sections:
* - Tool's Settings * - Tool's Settings
* - Default Settings [Move, Remove, etc] * - Default Settings [Move, Remove, etc]
*
* @returns {Element}
*/ */
public make(): void { public make(): void {
this.nodes.wrapper = $.make('div', this.CSS.wrapper); this.nodes.wrapper = $.make('div', this.CSS.wrapper);

View file

@ -3,7 +3,6 @@ import $ from '../../dom';
import { BlockToolConstructable } from '../../../../types'; import { BlockToolConstructable } from '../../../../types';
import * as _ from '../../utils'; import * as _ from '../../utils';
import { SavedData } from '../../../types-internal/block-data'; import { SavedData } from '../../../types-internal/block-data';
import Block from '../../block';
import Flipper from '../../flipper'; import Flipper from '../../flipper';
/** /**
@ -155,7 +154,7 @@ export default class ConversionToolbar extends Module {
* Replaces one Block with another * Replaces one Block with another
* For that Tools must provide import/export methods * For that Tools must provide import/export methods
* *
* @param {string} replacingToolName * @param {string} replacingToolName - name of Tool which replaces current
*/ */
public async replaceWithBlock(replacingToolName: string): Promise <void> { public async replaceWithBlock(replacingToolName: string): Promise <void> {
/** /**
@ -251,7 +250,7 @@ export default class ConversionToolbar extends Module {
const tools = this.Editor.Tools.blockTools; const tools = this.Editor.Tools.blockTools;
for (const toolName in tools) { for (const toolName in tools) {
if (!tools.hasOwnProperty(toolName)) { if (!Object.prototype.hasOwnProperty.call(tools, toolName)) {
continue; continue;
} }
@ -281,9 +280,9 @@ export default class ConversionToolbar extends Module {
/** /**
* Add tool to the Conversion Toolbar * Add tool to the Conversion Toolbar
* *
* @param toolName * @param {string} toolName - name of Tool to add
* @param toolIcon * @param {string} toolIcon - Tool icon
* @param title * @param {string} title - button title
*/ */
private addTool(toolName: string, toolIcon: string, title: string): void { private addTool(toolName: string, toolIcon: string, title: string): void {
const tool = $.make('div', [ ConversionToolbar.CSS.conversionTool ]); const tool = $.make('div', [ ConversionToolbar.CSS.conversionTool ]);

View file

@ -42,7 +42,7 @@ import * as _ from '../../utils';
* @classdesc Toolbar module * @classdesc Toolbar module
* *
* @typedef {Toolbar} Toolbar * @typedef {Toolbar} Toolbar
* @property {object} nodes * @property {object} nodes - Toolbar nodes
* @property {Element} nodes.wrapper - Toolbar main element * @property {Element} nodes.wrapper - Toolbar main element
* @property {Element} nodes.content - Zone with Plus button and toolbox. * @property {Element} nodes.content - Zone with Plus button and toolbox.
* @property {Element} nodes.actions - Zone with Block Settings and Remove Button * @property {Element} nodes.actions - Zone with Block Settings and Remove Button
@ -76,7 +76,7 @@ export default class Toolbar extends Module {
* *
* @returns {object} * @returns {object}
*/ */
public get CSS() { public get CSS(): {[name: string]: string} {
return { return {
toolbar: 'ce-toolbar', toolbar: 'ce-toolbar',
content: 'ce-toolbar__content', content: 'ce-toolbar__content',
@ -273,8 +273,8 @@ export default class Toolbar extends Module {
*/ */
public get plusButton(): {hide: () => void; show: () => void} { public get plusButton(): {hide: () => void; show: () => void} {
return { return {
hide: () => this.nodes.plusButton.classList.add(this.CSS.plusButtonHidden), hide: (): void => this.nodes.plusButton.classList.add(this.CSS.plusButtonHidden),
show: () => { show: (): void => {
if (this.Editor.Toolbox.isEmpty) { if (this.Editor.Toolbox.isEmpty) {
return; return;
} }
@ -290,10 +290,10 @@ export default class Toolbar extends Module {
*/ */
private get blockActions(): {hide: () => void; show: () => void} { private get blockActions(): {hide: () => void; show: () => void} {
return { return {
hide: () => { hide: (): void => {
this.nodes.actions.classList.remove(this.CSS.actionsOpened); this.nodes.actions.classList.remove(this.CSS.actionsOpened);
}, },
show: () => { show: (): void => {
this.nodes.actions.classList.add(this.CSS.actionsOpened); this.nodes.actions.classList.add(this.CSS.actionsOpened);
}, },
}; };
@ -301,8 +301,6 @@ export default class Toolbar extends Module {
/** /**
* Handler for Plus Button * Handler for Plus Button
*
* @param {MouseEvent} event
*/ */
private plusButtonClicked(): void { private plusButtonClicked(): void {
this.Editor.Toolbox.toggle(); this.Editor.Toolbox.toggle();

View file

@ -94,15 +94,15 @@ export default class InlineToolbar extends Module {
/** /**
* Inline Toolbar Tools * Inline Toolbar Tools
* *
* @returns Map<string, InlineTool> * @returns {Map<string, InlineTool>}
*/ */
get tools(): Map<string, InlineTool> { public get tools(): Map<string, InlineTool> {
if (!this.toolsInstances || this.toolsInstances.size === 0) { if (!this.toolsInstances || this.toolsInstances.size === 0) {
const allTools = this.inlineTools; const allTools = this.inlineTools;
this.toolsInstances = new Map(); this.toolsInstances = new Map();
for (const tool in allTools) { for (const tool in allTools) {
if (allTools.hasOwnProperty(tool)) { if (Object.prototype.hasOwnProperty.call(allTools, tool)) {
this.toolsInstances.set(tool, allTools[tool]); this.toolsInstances.set(tool, allTools[tool]);
} }
} }
@ -114,7 +114,7 @@ export default class InlineToolbar extends Module {
/** /**
* Making DOM * Making DOM
*/ */
public make() { public make(): void {
this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar); this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);
this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper); this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);
this.nodes.actions = $.make('div', this.CSS.actionsWrapper); this.nodes.actions = $.make('div', this.CSS.actionsWrapper);
@ -516,8 +516,8 @@ export default class InlineToolbar extends Module {
/** /**
* Add tool button and activate clicks * Add tool button and activate clicks
* *
* @param toolName * @param {string} toolName - name of Tool to add
* @param tool * @param {InlineTool} tool - Tool class instance
*/ */
private addTool(toolName: string, tool: InlineTool): void { private addTool(toolName: string, tool: InlineTool): void {
const { const {
@ -561,7 +561,7 @@ export default class InlineToolbar extends Module {
*/ */
const internalTools: string[] = Object const internalTools: string[] = Object
.entries(Tools.internalTools) .entries(Tools.internalTools)
.filter(([name, toolClass]: [string, ToolConstructable | ToolSettings]) => { .filter(([, toolClass]: [string, ToolConstructable | ToolSettings]) => {
if (_.isFunction(toolClass)) { if (_.isFunction(toolClass)) {
return toolClass[Tools.INTERNAL_SETTINGS.IS_INLINE]; return toolClass[Tools.INTERNAL_SETTINGS.IS_INLINE];
} }
@ -671,7 +671,7 @@ export default class InlineToolbar extends Module {
const result = {}; const result = {};
for (const tool in this.Editor.Tools.inline) { for (const tool in this.Editor.Tools.inline) {
if (this.Editor.Tools.inline.hasOwnProperty(tool)) { if (Object.prototype.hasOwnProperty.call(this.Editor.Tools.inline, tool)) {
const toolSettings = this.Editor.Tools.getToolSettings(tool); const toolSettings = this.Editor.Tools.getToolSettings(tool);
result[tool] = this.Editor.Tools.constructInline(this.Editor.Tools.inline[tool], toolSettings); result[tool] = this.Editor.Tools.constructInline(this.Editor.Tools.inline[tool], toolSettings);

View file

@ -19,10 +19,9 @@ export default class Toolbox extends Module {
/** /**
* CSS styles * CSS styles
* *
* @returns {{toolbox: string, toolboxButton string, toolboxButtonActive: string, * @returns {object.<string, string>}
* toolboxOpened: string, tooltip: string, tooltipShown: string, tooltipShortcut: string}}
*/ */
get CSS() { public get CSS(): {[name: string]: string} {
return { return {
toolbox: 'ce-toolbox', toolbox: 'ce-toolbox',
toolboxButton: 'ce-toolbox__button', toolboxButton: 'ce-toolbox__button',
@ -90,8 +89,8 @@ export default class Toolbox extends Module {
/** /**
* Toolbox Tool's button click handler * Toolbox Tool's button click handler
* *
* @param {MouseEvent|KeyboardEvent} event * @param {MouseEvent|KeyboardEvent} event - event that activates toolbox button
* @param {string} toolName * @param {string} toolName - button to activate
*/ */
public toolButtonActivate(event: MouseEvent|KeyboardEvent, toolName: string): void { public toolButtonActivate(event: MouseEvent|KeyboardEvent, toolName: string): void {
const tool = this.Editor.Tools.toolsClasses[toolName] as BlockToolConstructable; const tool = this.Editor.Tools.toolsClasses[toolName] as BlockToolConstructable;
@ -143,7 +142,7 @@ export default class Toolbox extends Module {
const tools = this.Editor.Tools.available; const tools = this.Editor.Tools.available;
for (const toolName in tools) { for (const toolName in tools) {
if (tools.hasOwnProperty(toolName)) { if (Object.prototype.hasOwnProperty.call(tools, toolName)) {
this.addTool(toolName, tools[toolName] as BlockToolConstructable); this.addTool(toolName, tools[toolName] as BlockToolConstructable);
} }
} }
@ -228,7 +227,7 @@ export default class Toolbox extends Module {
* Draw tooltip for toolbox tools * Draw tooltip for toolbox tools
* *
* @param {string} toolName - toolbox tool name * @param {string} toolName - toolbox tool name
* @returns { HTMLElement } * @returns {HTMLElement}
*/ */
private drawTooltip(toolName: string): HTMLElement { private drawTooltip(toolName: string): HTMLElement {
const toolSettings = this.Editor.Tools.getToolSettings(toolName); const toolSettings = this.Editor.Tools.getToolSettings(toolName);
@ -261,7 +260,7 @@ export default class Toolbox extends Module {
* @param {string} toolName - Tool name * @param {string} toolName - Tool name
* @param {string} shortcut - shortcut according to the ShortcutData Module format * @param {string} shortcut - shortcut according to the ShortcutData Module format
*/ */
private enableShortcut(tool: BlockToolConstructable, toolName: string, shortcut: string) { private enableShortcut(tool: BlockToolConstructable, toolName: string, shortcut: string): void {
this.Editor.Shortcuts.add({ this.Editor.Shortcuts.add({
name: shortcut, name: shortcut,
handler: (event: KeyboardEvent) => { handler: (event: KeyboardEvent) => {
@ -290,11 +289,8 @@ export default class Toolbox extends Module {
* @param {BlockToolConstructable} tool - Tool Class * @param {BlockToolConstructable} tool - Tool Class
* @param {string} toolName - Tool name * @param {string} toolName - Tool name
*/ */
private insertNewBlock(tool: BlockToolConstructable, toolName: string) { private insertNewBlock(tool: BlockToolConstructable, toolName: string): void {
const { BlockManager, Caret } = this.Editor; const { BlockManager, Caret } = this.Editor;
/**
* @type {Block}
*/
const { currentBlock } = BlockManager; const { currentBlock } = BlockManager;
let newBlock; let newBlock;

View file

@ -2,7 +2,8 @@ import Paragraph from '../tools/paragraph/dist/bundle';
import Module from '../__module'; import Module from '../__module';
import * as _ from '../utils'; import * as _ from '../utils';
import { import {
BlockToolConstructable, BlockTool,
BlockToolConstructable, BlockToolData, EditorConfig,
InlineTool, InlineTool,
InlineToolConstructable, Tool, InlineToolConstructable, Tool,
ToolConfig, ToolConfig,
@ -67,7 +68,7 @@ export default class Tools extends Module {
return this._inlineTools; return this._inlineTools;
} }
const tools = Object.entries(this.available).filter(([name, tool]) => { const tools = Object.entries(this.available).filter(([, tool]) => {
if (!tool[this.INTERNAL_SETTINGS.IS_INLINE]) { if (!tool[this.INTERNAL_SETTINGS.IS_INLINE]) {
return false; return false;
} }
@ -112,8 +113,7 @@ export default class Tools extends Module {
* Return editor block tools * Return editor block tools
*/ */
public get blockTools(): {[name: string]: BlockToolConstructable} { public get blockTools(): {[name: string]: BlockToolConstructable} {
// eslint-disable-next-line no-unused-vars const tools = Object.entries(this.available).filter(([, tool]) => {
const tools = Object.entries(this.available).filter(([name, tool]) => {
return !tool[this.INTERNAL_SETTINGS.IS_INLINE]; return !tool[this.INTERNAL_SETTINGS.IS_INLINE];
}); });
@ -134,7 +134,7 @@ export default class Tools extends Module {
* *
* @returns {object} * @returns {object}
*/ */
public get INTERNAL_SETTINGS() { public get INTERNAL_SETTINGS(): {[name: string]: string} {
return { return {
IS_ENABLED_LINE_BREAKS: 'enableLineBreaks', IS_ENABLED_LINE_BREAKS: 'enableLineBreaks',
IS_INLINE: 'isInline', IS_INLINE: 'isInline',
@ -151,7 +151,7 @@ export default class Tools extends Module {
* *
* return {object} * return {object}
*/ */
public get USER_SETTINGS() { public get USER_SETTINGS(): {[name: string]: string} {
return { return {
SHORTCUT: 'shortcut', SHORTCUT: 'shortcut',
TOOLBOX: 'toolbox', TOOLBOX: 'toolbox',
@ -196,7 +196,7 @@ export default class Tools extends Module {
/** /**
* @class * @class
* *
* @param {EditorConfig} config * @param {EditorConfig} config - Editor's configuration
*/ */
constructor({ config }) { constructor({ config }) {
super({ config }); super({ config });
@ -227,9 +227,9 @@ export default class Tools extends Module {
/** /**
* Creates instances via passed or default configuration * Creates instances via passed or default configuration
* *
* @returns {Promise} * @returns {Promise<void>}
*/ */
public prepare() { public prepare(): Promise<void> {
this.validateTools(); this.validateTools();
/** /**
@ -237,7 +237,7 @@ export default class Tools extends Module {
*/ */
this.config.tools = _.deepMerge({}, this.internalTools, this.config.tools); this.config.tools = _.deepMerge({}, this.internalTools, this.config.tools);
if (!this.config.hasOwnProperty('tools') || Object.keys(this.config.tools).length === 0) { if (!Object.prototype.hasOwnProperty.call(this.config, 'tools') || Object.keys(this.config.tools).length === 0) {
throw Error('Can\'t start without tools'); throw Error('Can\'t start without tools');
} }
@ -298,26 +298,30 @@ export default class Tools extends Module {
} }
/** /**
* to see how it works {@link Util#sequence} * to see how it works {@link '../utils.ts#sequence'}
*/ */
return _.sequence(sequenceData, (data: any) => { return _.sequence(sequenceData, (data: {toolName: string}) => {
this.success(data); this.success(data);
}, (data) => { }, (data: {toolName: string}) => {
this.fallback(data); this.fallback(data);
}); });
} }
/** /**
* @param {ChainData.data} data - append tool to available list * Success callback
*
* @param {object} data - append tool to available list
*/ */
public success(data) { public success(data: {toolName: string}): void {
this.toolsAvailable[data.toolName] = this.toolsClasses[data.toolName]; this.toolsAvailable[data.toolName] = this.toolsClasses[data.toolName];
} }
/** /**
* @param {ChainData.data} data - append tool to unavailable list * Fail callback
*
* @param {object} data - append tool to unavailable list
*/ */
public fallback(data) { public fallback(data: {toolName: string}): void {
this.toolsUnavailable[data.toolName] = this.toolsClasses[data.toolName]; this.toolsUnavailable[data.toolName] = this.toolsClasses[data.toolName];
} }
@ -325,11 +329,12 @@ export default class Tools extends Module {
* Return Tool`s instance * Return Tool`s instance
* *
* @param {string} tool tool name * @param {string} tool tool name
* @param {BlockToolData} data initial data * @param {object} data initial data
*
* @returns {BlockTool} * @returns {BlockTool}
*/ */
public construct(tool, data) { public construct(tool: string, data: BlockToolData): BlockTool {
const Plugin = this.toolsClasses[tool]; const Plugin = this.toolsClasses[tool] as BlockToolConstructable;
/** /**
* Configuration to be passed to the Tool's constructor * Configuration to be passed to the Tool's constructor
@ -341,9 +346,6 @@ export default class Tools extends Module {
config.placeholder = this.config.placeholder; config.placeholder = this.config.placeholder;
} }
/**
* @type {{api: API, config: ({}), data: BlockToolData}}
*/
const constructorOptions = { const constructorOptions = {
api: this.Editor.API.methods, api: this.Editor.API.methods,
config, config,
@ -356,14 +358,12 @@ export default class Tools extends Module {
/** /**
* Return Inline Tool's instance * Return Inline Tool's instance
* *
* @param {InlineTool} tool * @param {InlineTool} tool - Inline Tool instance
* @param {ToolSettings} toolSettings * @param {ToolSettings} toolSettings - tool settings
*
* @returns {InlineTool} instance * @returns {InlineTool} instance
*/ */
public constructInline(tool: InlineToolConstructable, toolSettings: ToolSettings = {} as ToolSettings): InlineTool { public constructInline(tool: InlineToolConstructable, toolSettings: ToolSettings = {} as ToolSettings): InlineTool {
/**
* @type {{api: API}}
*/
const constructorOptions = { const constructorOptions = {
api: this.Editor.API.methods, api: this.Editor.API.methods,
config: (toolSettings[this.USER_SETTINGS.CONFIG] || {}) as ToolSettings, config: (toolSettings[this.USER_SETTINGS.CONFIG] || {}) as ToolSettings,
@ -377,22 +377,41 @@ export default class Tools extends Module {
* Check if passed Tool is an instance of Initial Block Tool * Check if passed Tool is an instance of Initial Block Tool
* *
* @param {Tool} tool - Tool to check * @param {Tool} tool - Tool to check
*
* @returns {boolean} * @returns {boolean}
*/ */
public isInitial(tool) { public isInitial(tool): boolean {
return tool instanceof this.available[this.config.initialBlock]; return tool instanceof this.available[this.config.initialBlock];
} }
/** /**
* Return Tool's config by name * Return Tool's config by name
* *
* @param {string} toolName * @param {string} toolName - name of tool
*
* @returns {ToolSettings} * @returns {ToolSettings}
*/ */
public getToolSettings(toolName): ToolSettings { public getToolSettings(toolName): ToolSettings {
return this.toolsSettings[toolName]; return this.toolsSettings[toolName];
} }
/**
* Returns internal tools
* Includes Bold, Italic, Link and Paragraph
*/
public get internalTools(): {[toolName: string]: ToolConstructable|ToolSettings} {
return {
bold: { class: BoldInlineTool },
italic: { class: ItalicInlineTool },
link: { class: LinkInlineTool },
paragraph: {
class: Paragraph,
inlineToolbar: true,
},
stub: { class: Stub },
};
}
/** /**
* Binds prepare function of plugins with user or default config * Binds prepare function of plugins with user or default config
* *
@ -408,7 +427,7 @@ export default class Tools extends Module {
> = []; > = [];
for (const toolName in this.toolsClasses) { for (const toolName in this.toolsClasses) {
if (this.toolsClasses.hasOwnProperty(toolName)) { if (Object.prototype.hasOwnProperty.call(this.toolsClasses, toolName)) {
const toolClass = this.toolsClasses[toolName]; const toolClass = this.toolsClasses[toolName];
if (typeof toolClass.prepare === 'function') { if (typeof toolClass.prepare === 'function') {
@ -434,12 +453,12 @@ export default class Tools extends Module {
/** /**
* Validate Tools configuration objects and throw Error for user if it is invalid * Validate Tools configuration objects and throw Error for user if it is invalid
*/ */
private validateTools() { private validateTools(): void {
/** /**
* Check Tools for a class containing * Check Tools for a class containing
*/ */
for (const toolName in this.config.tools) { for (const toolName in this.config.tools) {
if (this.config.tools.hasOwnProperty(toolName)) { if (Object.prototype.hasOwnProperty.call(this.config.tools, toolName)) {
if (toolName in this.internalTools) { if (toolName in this.internalTools) {
return; return;
} }
@ -454,21 +473,4 @@ export default class Tools extends Module {
} }
} }
} }
/**
* Returns internal tools
* Includes Bold, Italic, Link and Paragraph
*/
get internalTools() {
return {
bold: { class: BoldInlineTool },
italic: { class: ItalicInlineTool },
link: { class: LinkInlineTool },
paragraph: {
class: Paragraph,
inlineToolbar: true,
},
stub: { class: Stub },
};
}
} }

View file

@ -1,3 +1,4 @@
/* eslint-disable jsdoc/no-undefined-types */
import Module from '../__module'; import Module from '../__module';
/** /**
@ -21,7 +22,7 @@ export default class Tooltip extends Module {
/** /**
* @class * @class
* @param {EditorConfig} * @param {EditorConfig} - Editor's config
*/ */
constructor({ config }: ModuleConfig) { constructor({ config }: ModuleConfig) {
super({ config }); super({ config });

View file

@ -1,3 +1,4 @@
/* eslint-disable jsdoc/no-undefined-types */
/** /**
* Prebuilded sprite of SVG icons * Prebuilded sprite of SVG icons
*/ */
@ -28,8 +29,8 @@ import Flipper from '../flipper';
* *
* @typedef {UI} UI * @typedef {UI} UI
* @property {EditorConfig} config - editor configuration {@link EditorJS#configuration} * @property {EditorConfig} config - editor configuration {@link EditorJS#configuration}
* @property {Object} Editor - available editor modules {@link EditorJS#moduleInstances} * @property {object} Editor - available editor modules {@link EditorJS#moduleInstances}
* @property {Object} nodes - * @property {object} nodes -
* @property {Element} nodes.holder - element where we need to append redactor * @property {Element} nodes.holder - element where we need to append redactor
* @property {Element} nodes.wrapper - <codex-editor> * @property {Element} nodes.wrapper - <codex-editor>
* @property {Element} nodes.redactor - <ce-redactor> * @property {Element} nodes.redactor - <ce-redactor>
@ -37,7 +38,8 @@ import Flipper from '../flipper';
export default class UI extends Module { export default class UI extends Module {
/** /**
* Editor.js UI CSS class names * Editor.js UI CSS class names
* @return {{editorWrapper: string, editorZone: string}} *
* @returns {{editorWrapper: string, editorZone: string}}
*/ */
public get CSS(): { public get CSS(): {
editorWrapper: string; editorWrapperNarrow: string; editorZone: string; editorZoneHidden: string; editorWrapper: string; editorWrapperNarrow: string; editorZone: string; editorZoneHidden: string;
@ -55,7 +57,8 @@ export default class UI extends Module {
/** /**
* Return Width of center column of Editor * Return Width of center column of Editor
* @return {DOMRect} *
* @returns {DOMRect}
*/ */
public get contentRect(): DOMRect { public get contentRect(): DOMRect {
if (this.contentRectCache) { if (this.contentRectCache) {
@ -82,6 +85,7 @@ export default class UI extends Module {
/** /**
* Flag that became true on mobile viewport * Flag that became true on mobile viewport
*
* @type {boolean} * @type {boolean}
*/ */
public isMobile = false; public isMobile = false;
@ -98,12 +102,14 @@ export default class UI extends Module {
/** /**
* Cache for center column rectangle info * Cache for center column rectangle info
* Invalidates on window resize * Invalidates on window resize
*
* @type {DOMRect} * @type {DOMRect}
*/ */
private contentRectCache: DOMRect = undefined; private contentRectCache: DOMRect = undefined;
/** /**
* Handle window resize only when it finished * Handle window resize only when it finished
*
* @type {() => void} * @type {() => void}
*/ */
private resizeDebouncer: () => void = _.debounce(() => { private resizeDebouncer: () => void = _.debounce(() => {
@ -184,7 +190,8 @@ export default class UI extends Module {
/** /**
* Check if one of Toolbar is opened * Check if one of Toolbar is opened
* Used to prevent global keydowns (for example, Enter) conflicts with Enter-on-toolbar * Used to prevent global keydowns (for example, Enter) conflicts with Enter-on-toolbar
* @return {boolean} *
* @returns {boolean}
*/ */
public get someToolbarOpened(): boolean { public get someToolbarOpened(): boolean {
const { Toolbox, BlockSettings, InlineToolbar, ConversionToolbar } = this.Editor; const { Toolbox, BlockSettings, InlineToolbar, ConversionToolbar } = this.Editor;
@ -226,17 +233,19 @@ export default class UI extends Module {
/** /**
* Check for mobile mode and cache a result * Check for mobile mode and cache a result
*/ */
private checkIsMobile() { private checkIsMobile(): void {
this.isMobile = window.innerWidth < 650; this.isMobile = window.innerWidth < 650;
} }
/** /**
* Makes Editor.js interface * Makes Editor.js interface
* @return {Promise<void>} *
* @returns {Promise<void>}
*/ */
private async make(): Promise<void> { private async make(): Promise<void> {
/** /**
* Element where we need to append Editor.js * Element where we need to append Editor.js
*
* @type {Element} * @type {Element}
*/ */
this.nodes.holder = $.getHolder(this.config.holder); this.nodes.holder = $.getHolder(this.config.holder);
@ -270,6 +279,7 @@ export default class UI extends Module {
/** /**
* Load CSS * Load CSS
*/ */
// eslint-disable-next-line @typescript-eslint/no-var-requires
const styles = require('../../styles/main.css'); const styles = require('../../styles/main.css');
/** /**
@ -340,7 +350,8 @@ export default class UI extends Module {
/** /**
* All keydowns on document * All keydowns on document
* @param {Event} event *
* @param {KeyboardEvent} event - keyboard event
*/ */
private documentKeydown(event: KeyboardEvent): void { private documentKeydown(event: KeyboardEvent): void {
switch (event.keyCode) { switch (event.keyCode) {
@ -358,7 +369,8 @@ export default class UI extends Module {
/** /**
* Ignore all other document's keydown events * Ignore all other document's keydown events
* @param {KeyboardEvent} event *
* @param {KeyboardEvent} event - keyboard event
*/ */
private defaultBehaviour(event: KeyboardEvent): void { private defaultBehaviour(event: KeyboardEvent): void {
const keyDownOnEditor = (event.target as HTMLElement).closest(`.${this.CSS.editorWrapper}`); const keyDownOnEditor = (event.target as HTMLElement).closest(`.${this.CSS.editorWrapper}`);
@ -384,7 +396,7 @@ export default class UI extends Module {
} }
/** /**
* @param {KeyboardEvent} event * @param {KeyboardEvent} event - keyboard event
*/ */
private backspacePressed(event: KeyboardEvent): void { private backspacePressed(event: KeyboardEvent): void {
const { BlockManager, BlockSelection, Caret } = this.Editor; const { BlockManager, BlockSelection, Caret } = this.Editor;
@ -410,7 +422,8 @@ export default class UI extends Module {
/** /**
* Enter pressed on document * Enter pressed on document
* @param event *
* @param {KeyboardEvent} event - keyboard event
*/ */
private enterPressed(event: KeyboardEvent): void { private enterPressed(event: KeyboardEvent): void {
const { BlockManager, BlockSelection, Caret } = this.Editor; const { BlockManager, BlockSelection, Caret } = this.Editor;
@ -468,7 +481,8 @@ export default class UI extends Module {
/** /**
* All clicks on document * All clicks on document
* @param {MouseEvent} event - Click *
* @param {MouseEvent} event - Click event
*/ */
private documentClicked(event: MouseEvent): void { private documentClicked(event: MouseEvent): void {
/** /**
@ -521,6 +535,8 @@ export default class UI extends Module {
* Also: * Also:
* - Move and show the Toolbar * - Move and show the Toolbar
* - Set a Caret * - Set a Caret
*
* @param {MouseEvent | TouchEvent} event - touch or mouse event
*/ */
private documentTouched(event: MouseEvent | TouchEvent): void { private documentTouched(event: MouseEvent | TouchEvent): void {
let clickedNode = event.target as HTMLElement; let clickedNode = event.target as HTMLElement;
@ -571,7 +587,7 @@ export default class UI extends Module {
/** /**
* All clicks on the redactor zone * All clicks on the redactor zone
* *
* @param {MouseEvent} event * @param {MouseEvent} event - click event
* *
* @description * @description
* - By clicks on the Editor's bottom zone: * - By clicks on the Editor's bottom zone:
@ -628,7 +644,8 @@ export default class UI extends Module {
/** /**
* Handle selection changes on mobile devices * Handle selection changes on mobile devices
* Uses for showing the Inline Toolbar * Uses for showing the Inline Toolbar
* @param {Event} event *
* @param {Event} event - selection event
*/ */
private selectionChanged(event: Event): void { private selectionChanged(event: Event): void {
const focusedElement = Selection.anchorElement as Element; const focusedElement = Selection.anchorElement as Element;

View file

@ -18,7 +18,9 @@ interface Element {
* would be selected by the specified selector string; * would be selected by the specified selector string;
* otherwise, returns false. * otherwise, returns false.
* *
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill} * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill}
*
* @param {string} s - selector
*/ */
if (!Element.prototype.matches) { if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.matches = Element.prototype.matchesSelector ||
@ -26,7 +28,7 @@ if (!Element.prototype.matches) {
Element.prototype.msMatchesSelector || Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector || Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector || Element.prototype.webkitMatchesSelector ||
function (s) { function (s): boolean {
const matches = (this.document || this.ownerDocument).querySelectorAll(s); const matches = (this.document || this.ownerDocument).querySelectorAll(s);
let i = matches.length; let i = matches.length;
@ -43,10 +45,12 @@ if (!Element.prototype.matches) {
* matches the selectors given in parameter. * matches the selectors given in parameter.
* If there isn't such an ancestor, it returns null. * If there isn't such an ancestor, it returns null.
* *
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill} * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill}
*
* @param {string} s - selector
*/ */
if (!Element.prototype.closest) { if (!Element.prototype.closest) {
Element.prototype.closest = function (s) { Element.prototype.closest = function (s): Element | null {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
let el = this; let el = this;
@ -71,20 +75,22 @@ if (!Element.prototype.closest) {
* or DOMString objects before the first child of the ParentNode. * or DOMString objects before the first child of the ParentNode.
* DOMString objects are inserted as equivalent Text nodes. * DOMString objects are inserted as equivalent Text nodes.
* *
* {@link https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend#Polyfill} * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend#Polyfill}
*
* @param {Node | Node[] | string | string[]} nodes - nodes to prepend
*/ */
if (!Element.prototype.prepend) { if (!Element.prototype.prepend) {
Element.prototype.prepend = function prepend(nodes: Node|Node[]|any) { Element.prototype.prepend = function prepend(nodes: Array<Node | string> | Node | string): void {
const docFrag = document.createDocumentFragment(); const docFrag = document.createDocumentFragment();
if (!Array.isArray(nodes)) { if (!Array.isArray(nodes)) {
nodes = [ nodes ]; nodes = [ nodes ];
} }
nodes.forEach((node: Node|any) => { nodes.forEach((node: Node | string) => {
const isNode = node instanceof Node; const isNode = node instanceof Node;
docFrag.appendChild(isNode ? node : document.createTextNode(String(node))); docFrag.appendChild(isNode ? node as Node : document.createTextNode(node as string));
}); });
this.insertBefore(docFrag, this.firstChild); this.insertBefore(docFrag, this.firstChild);

View file

@ -39,7 +39,7 @@ export default class SelectionUtils {
* *
* @returns {{editorWrapper: string, editorZone: string}} * @returns {{editorWrapper: string, editorZone: string}}
*/ */
static get CSS(): { editorWrapper: string; editorZone: string } { public static get CSS(): { editorWrapper: string; editorZone: string } {
return { return {
editorWrapper: 'codex-editor', editorWrapper: 'codex-editor',
editorZone: 'codex-editor__redactor', editorZone: 'codex-editor__redactor',
@ -52,7 +52,7 @@ export default class SelectionUtils {
* *
* @returns {Node|null} * @returns {Node|null}
*/ */
static get anchorNode(): Node | null { public static get anchorNode(): Node | null {
const selection = window.getSelection(); const selection = window.getSelection();
return selection ? selection.anchorNode : null; return selection ? selection.anchorNode : null;
@ -63,7 +63,7 @@ export default class SelectionUtils {
* *
* @returns {Element|null} * @returns {Element|null}
*/ */
static get anchorElement(): Element | null { public static get anchorElement(): Element | null {
const selection = window.getSelection(); const selection = window.getSelection();
if (!selection) { if (!selection) {
@ -89,7 +89,7 @@ export default class SelectionUtils {
* *
* @returns {number|null} * @returns {number|null}
*/ */
static get anchorOffset(): number | null { public static get anchorOffset(): number | null {
const selection = window.getSelection(); const selection = window.getSelection();
return selection ? selection.anchorOffset : null; return selection ? selection.anchorOffset : null;
@ -100,7 +100,7 @@ export default class SelectionUtils {
* *
* @returns {boolean|null} * @returns {boolean|null}
*/ */
static get isCollapsed(): boolean | null { public static get isCollapsed(): boolean | null {
const selection = window.getSelection(); const selection = window.getSelection();
return selection ? selection.isCollapsed : null; return selection ? selection.isCollapsed : null;
@ -111,7 +111,7 @@ export default class SelectionUtils {
* *
* @returns {boolean} * @returns {boolean}
*/ */
static get isAtEditor(): boolean { public static get isAtEditor(): boolean {
const selection = SelectionUtils.get(); const selection = SelectionUtils.get();
/** /**
@ -140,7 +140,7 @@ export default class SelectionUtils {
* *
* @returns {Range|null} * @returns {Range|null}
*/ */
static get range(): Range { public static get range(): Range | null {
const selection = window.getSelection(); const selection = window.getSelection();
return selection && selection.rangeCount ? selection.getRangeAt(0) : null; return selection && selection.rangeCount ? selection.getRangeAt(0) : null;
@ -149,9 +149,9 @@ export default class SelectionUtils {
/** /**
* Calculates position and size of selected text * Calculates position and size of selected text
* *
* @returns {{x, y, width, height, top?, left?, bottom?, right?}} * @returns {DOMRect | ClientRect}
*/ */
static get rect(): DOMRect | ClientRect { public static get rect(): DOMRect | ClientRect {
let sel: Selection | MSSelection = (document as Document).selection, let sel: Selection | MSSelection = (document as Document).selection,
range: TextRange | Range; range: TextRange | Range;
@ -224,20 +224,15 @@ export default class SelectionUtils {
* *
* @returns {string} * @returns {string}
*/ */
static get text(): string { public static get text(): string {
return window.getSelection ? window.getSelection().toString() : ''; return window.getSelection ? window.getSelection().toString() : '';
} }
/** /**
* Returns window SelectionUtils * Selection instances
* {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
* *
* @returns {Selection} * @todo Check if this is still relevant
*/ */
public static get(): Selection {
return window.getSelection();
}
public instance: Selection = null; public instance: Selection = null;
public selection: Selection = null; public selection: Selection = null;
@ -261,10 +256,20 @@ export default class SelectionUtils {
private readonly commandBackground: string = 'backColor'; private readonly commandBackground: string = 'backColor';
private readonly commandRemoveFormat: string = 'removeFormat'; private readonly commandRemoveFormat: string = 'removeFormat';
/**
* Returns window SelectionUtils
* {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
*
* @returns {Selection}
*/
public static get(): Selection {
return window.getSelection();
}
/** /**
* Removes fake background * Removes fake background
*/ */
public removeFakeBackground() { public removeFakeBackground(): void {
if (!this.isFakeBackgroundEnabled) { if (!this.isFakeBackgroundEnabled) {
return; return;
} }
@ -276,7 +281,7 @@ export default class SelectionUtils {
/** /**
* Sets fake background * Sets fake background
*/ */
public setFakeBackground() { public setFakeBackground(): void {
document.execCommand(this.commandBackground, false, '#a8d6ff'); document.execCommand(this.commandBackground, false, '#a8d6ff');
this.isFakeBackgroundEnabled = true; this.isFakeBackgroundEnabled = true;
@ -329,6 +334,7 @@ export default class SelectionUtils {
* @param {string} tagName - tag to found * @param {string} tagName - tag to found
* @param {string} [className] - tag's class name * @param {string} [className] - tag's class name
* @param {number} [searchDepth] - count of tags that can be included. For better performance. * @param {number} [searchDepth] - count of tags that can be included. For better performance.
*
* @returns {HTMLElement|null} * @returns {HTMLElement|null}
*/ */
public findParentTag(tagName: string, className?: string, searchDepth = 10): HTMLElement | null { public findParentTag(tagName: string, className?: string, searchDepth = 10): HTMLElement | null {
@ -402,7 +408,7 @@ export default class SelectionUtils {
/** /**
* Expands selection range to the passed parent node * Expands selection range to the passed parent node
* *
* @param {HTMLElement} element * @param {HTMLElement} element - element which contents should be selcted
*/ */
public expandToTag(element: HTMLElement): void { public expandToTag(element: HTMLElement): void {
const selection = window.getSelection(); const selection = window.getSelection();

View file

@ -1,6 +1,11 @@
import $ from '../../dom'; import $ from '../../dom';
import { BlockTool, BlockToolData } from '../../../../types'; import { BlockTool, BlockToolData } from '../../../../types';
export interface StubData extends BlockToolData{
title: string;
savedData: BlockToolData;
}
/** /**
* *
*/ */
@ -38,11 +43,9 @@ export default class Stub implements BlockTool {
private readonly savedData: BlockToolData; private readonly savedData: BlockToolData;
/** /**
* @param data * @param {BlockToolData} data - stub tool data
* @param config
* @param api
*/ */
constructor({ data, config, api }) { constructor({ data }: {data: StubData}) {
this.title = data.title || 'Error'; this.title = data.title || 'Error';
this.subtitle = 'The block can not be displayed correctly.'; this.subtitle = 'The block can not be displayed correctly.';
this.savedData = data.savedData; this.savedData = data.savedData;

View file

@ -22,10 +22,13 @@ declare const VERSION: string;
/** /**
* @typedef {object} ChainData * @typedef {object} ChainData
* @property {object} data - data that will be passed to the success or fallback * @property {object} data - data that will be passed to the success or fallback
* @property {Function} function - function's that must be called asynchronically * @property {Function} function - function's that must be called asynchronously
*
* @interface ChainData
*/ */
export interface ChainData { export interface ChainData {
data?: any; data?: object;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function: (...args: any[]) => any; function: (...args: any[]) => any;
} }
@ -79,6 +82,7 @@ function _log(
labeled: boolean, labeled: boolean,
msg: string, msg: string,
type = 'log', type = 'log',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
args?: any, args?: any,
style = 'color: inherit' style = 'color: inherit'
): void { ): void {
@ -172,7 +176,8 @@ export const logLabeled = _log.bind(window, true);
/** /**
* Returns true if passed key code is printable (a-Z, 0-9, etc) character. * Returns true if passed key code is printable (a-Z, 0-9, etc) character.
* *
* @param {number} keyCode * @param {number} keyCode - key code
*
* @returns {boolean} * @returns {boolean}
*/ */
export function isPrintableKey(keyCode: number): boolean { export function isPrintableKey(keyCode: number): boolean {
@ -196,24 +201,24 @@ export function isPrintableKey(keyCode: number): boolean {
export async function sequence( export async function sequence(
chains: ChainData[], chains: ChainData[],
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
success: (data: any) => void = (): void => {}, success: (data: object) => void = (): void => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
fallback: (data: any) => void = (): void => {}, fallback: (data: object) => void = (): void => {}
): Promise<void> { ): Promise<void> {
/** /**
* Decorator * Decorator
* *
* @param {ChainData} chainData * @param {ChainData} chainData - Chain data
* *
* @param {Function} successCallback * @param {Function} successCallback - success callback
* @param {Function} fallbackCallback * @param {Function} fallbackCallback - fail callback
* *
* @returns {Promise} * @returns {Promise}
*/ */
async function waitNextBlock( async function waitNextBlock(
chainData: ChainData, chainData: ChainData,
successCallback: (data: any) => void, successCallback: (data: object) => void,
fallbackCallback: (data: any) => void fallbackCallback: (data: object) => void
): Promise<void> { ): Promise<void> {
try { try {
await chainData.function(chainData.data); await chainData.function(chainData.data);
@ -240,10 +245,11 @@ export async function sequence(
/** /**
* Make array from array-like collection * Make array from array-like collection
* *
* @param {ArrayLike} collection * @param {ArrayLike} collection - collection to convert to array
* *
* @returns {Array} * @returns {Array}
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function array(collection: ArrayLike<any>): any[] { export function array(collection: ArrayLike<any>): any[] {
return Array.prototype.slice.call(collection); return Array.prototype.slice.call(collection);
} }
@ -251,19 +257,23 @@ export function array(collection: ArrayLike<any>): any[] {
/** /**
* Check if passed variable is a function * Check if passed variable is a function
* *
* @param {*} fn * @param {*} fn - function to check
*
* @returns {boolean} * @returns {boolean}
*/ */
export function isFunction(fn: any): boolean { // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isFunction(fn: any): fn is Function {
return typeof fn === 'function'; return typeof fn === 'function';
} }
/** /**
* Check if passed function is a class * Check if passed function is a class
* *
* @param {Function} fn * @param {Function} fn - function to check
*
* @returns {boolean} * @returns {boolean}
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isClass(fn: any): boolean { export function isClass(fn: any): boolean {
return typeof fn === 'function' && /^\s*class\s+/.test(fn.toString()); return typeof fn === 'function' && /^\s*class\s+/.test(fn.toString());
} }
@ -271,7 +281,8 @@ export function isClass(fn: any): boolean {
/** /**
* Checks if object is empty * Checks if object is empty
* *
* @param {object} object * @param {object} object - object to check
*
* @returns {boolean} * @returns {boolean}
*/ */
export function isEmpty(object: object): boolean { export function isEmpty(object: object): boolean {
@ -288,18 +299,20 @@ export function isEmpty(object: object): boolean {
* @param {*} object - object to check * @param {*} object - object to check
* @returns {boolean} * @returns {boolean}
*/ */
export function isPromise(object: any): boolean { // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isPromise(object: any): object is Promise<any> {
return Promise.resolve(object) === object; return Promise.resolve(object) === object;
} }
/** /**
* Delays method execution * Delays method execution
* *
* @param {Function} method * @param {Function} method - method to execute
* @param {number} timeout * @param {number} timeout - timeout in ms
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function delay(method: (...args: any[]) => any, timeout: number) { export function delay(method: (...args: any[]) => any, timeout: number) {
return function() { return function (): void {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
const context = this, const context = this,
// eslint-disable-next-line prefer-rest-params // eslint-disable-next-line prefer-rest-params
@ -312,8 +325,9 @@ export function delay(method: (...args: any[]) => any, timeout: number) {
/** /**
* Get file extension * Get file extension
* *
* @param {File} file * @param {File} file - file
* @returns string *
* @returns {string}
*/ */
export function getFileExtension(file: File): string { export function getFileExtension(file: File): string {
return file.name.split('.').pop(); return file.name.split('.').pop();
@ -322,8 +336,9 @@ export function getFileExtension(file: File): string {
/** /**
* Check if string is MIME type * Check if string is MIME type
* *
* @param {string} type * @param {string} type - string to check
* @returns boolean *
* @returns {boolean}
*/ */
export function isValidMimeType(type: string): boolean { export function isValidMimeType(type: string): boolean {
return /^[-\w]+\/([-+\w]+|\*)$/.test(type); return /^[-\w]+\/([-+\w]+|\*)$/.test(type);
@ -416,22 +431,35 @@ export function getUserOS(): {[key: string]: boolean} {
/** /**
* Capitalizes first letter of the string * Capitalizes first letter of the string
* *
* @param {string} text * @param {string} text - text to capitalize
*
* @returns {string} * @returns {string}
*/ */
export function capitalize(text: string): string { export function capitalize(text: string): string {
return text[0].toUpperCase() + text.slice(1); return text[0].toUpperCase() + text.slice(1);
} }
/**
* Return string representation of the object type
*
* @param {*} object - object to get type
*
* @returns {string}
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function typeOf(object: any): string {
return Object.prototype.toString.call(object).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
/** /**
* Merge to objects recursively * Merge to objects recursively
* *
* @param {object} target * @param {object} target - merge target
* @param {object[]} sources * @param {object[]} sources - merge sources
* @returns {object} * @returns {object}
*/ */
export function deepMerge(target, ...sources): {[key: string]: any} { export function deepMerge<T extends object>(target, ...sources): T {
const isObject = (item) => item && typeOf(item) === 'object'; const isObject = (item): item is object => item && typeOf(item) === 'object';
if (!sources.length) { if (!sources.length) {
return target; return target;
@ -467,15 +495,6 @@ export function deepMerge(target, ...sources): {[key: string]: any} {
*/ */
export const isTouchSupported: boolean = 'ontouchstart' in document.documentElement; export const isTouchSupported: boolean = 'ontouchstart' in document.documentElement;
/**
* Return string representation of the object type
*
* @param {any} object
*/
export function typeOf(object: any): string {
return Object.prototype.toString.call(object).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
/** /**
* Make shortcut command more human-readable * Make shortcut command more human-readable
* *
@ -511,7 +530,7 @@ export function beautifyShortcut(shortcut: string): string {
* If url has `one slash`, then it concatenates with window location origin * If url has `one slash`, then it concatenates with window location origin
* or when url has `two lack` it appends only protocol * or when url has `two lack` it appends only protocol
* *
* @param {string} url * @param {string} url - url to prettify
*/ */
export function getValidUrl(url: string): string { export function getValidUrl(url: string): string {
try { try {

View file

@ -2,4 +2,4 @@
* Object returned by Tool's {@link BlockTool#save} method * Object returned by Tool's {@link BlockTool#save} method
* Specified by Tool developer, so leave it as object * Specified by Tool developer, so leave it as object
*/ */
export type BlockToolData = object; export type BlockToolData<T extends object = any> = T;

View file

@ -1,10 +1,11 @@
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, BaseToolConstructorOptions} 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'; import { MoveEvent } from './hook-events';
/** /**
* Describe Block Tool object * Describe Block Tool object
* @see {@link docs/tools.md} * @see {@link docs/tools.md}
@ -73,6 +74,15 @@ export interface BlockTool extends BaseTool {
moved?(event: MoveEvent): void; moved?(event: MoveEvent): void;
} }
/**
* Describe constructor parameters
*/
export interface BlockToolConstructorOptions extends BaseToolConstructorOptions {
api: API;
data: BlockToolData;
config?: ToolConfig;
}
export interface BlockToolConstructable extends BaseToolConstructable { export interface BlockToolConstructable extends BaseToolConstructable {
/** /**
* Tool's Toolbox settings * Tool's Toolbox settings
@ -101,7 +111,10 @@ export interface BlockToolConstructable extends BaseToolConstructable {
/** /**
* @constructor * @constructor
*
* @param {BlockToolConstructorOptions} config - constructor parameters
*
* @return {BlockTool} * @return {BlockTool}
*/ */
new(config: { api: API, config: ToolConfig, data: BlockToolData }): BlockTool; new(config: BlockToolConstructorOptions): BlockTool;
} }

View file

@ -12,4 +12,4 @@ export * from './paste-events';
export * from './hook-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 = BlockToolConstructable | InlineToolConstructable;

View file

@ -1,4 +1,5 @@
import {BaseTool, BaseToolConstructable} from './tool'; import {BaseTool, BaseToolConstructable} from './tool';
import {API, ToolConfig} from "../index";
/** /**
* Base structure for the Inline Toolbar Tool * Base structure for the Inline Toolbar Tool
*/ */
@ -34,4 +35,20 @@ export interface InlineTool extends BaseTool {
clear?(): void; clear?(): void;
} }
export interface InlineToolConstructable extends BaseToolConstructable {}
/**
* Describe constructor parameters
*/
export interface InlineToolConstructorOptions {
api: API;
config?: ToolConfig;
}
export interface InlineToolConstructable extends BaseToolConstructable {
/**
* Constructor
*
* @param {InlineToolConstructorOptions} config - constructor parameters
*/
new(config: InlineToolConstructorOptions): BaseTool;
}

View file

@ -1,4 +1,4 @@
import {API, ToolSettings} from '../index'; import {API, BlockToolData, ToolSettings} from '../index';
import {ToolConfig} from './tool-config'; import {ToolConfig} from './tool-config';
import {SanitizerConfig} from '../configs'; import {SanitizerConfig} from '../configs';
@ -30,11 +30,6 @@ export interface BaseToolConstructable {
*/ */
title?: string; title?: string;
/**
* Describe constructor parameters
*/
new (config: {api: API, config?: ToolSettings}): BaseTool;
/** /**
* Tool`s prepare method. Can be async * Tool`s prepare method. Can be async
* @param data * @param data