fix: errors caused by events fired while editor is not initialized yet (#2532)

* fix(init): errors cause by events fired while editor is not initialized yet

* Update package.json
This commit is contained in:
Peter Savchenko 2023-11-08 22:35:52 +03:00 committed by GitHub
parent af6b64a3e6
commit 5e8fe06dd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 20 deletions

View file

@ -9,6 +9,7 @@
- `Fix` — When the focusing Block is out of the viewport, the page will be scrolled.
- `Fix``blocks.render()` won't lead the `onChange` call in Safari
- `Fix` — Editor wrapper element growing on the Inline Toolbar close
- `Fix` — Fix errors thrown by clicks on a document when the editor is being initialized
### 2.28.2

View file

@ -1,6 +1,6 @@
{
"name": "@editorjs/editorjs",
"version": "2.29.0-rc.5",
"version": "2.29.0-rc.6",
"description": "Editor.js — Native JS, based on API and Open Source",
"main": "dist/editorjs.umd.js",
"module": "dist/editorjs.mjs",

View file

@ -744,7 +744,11 @@ export default class BlockManager extends Module {
* @param {Node} childNode - node to get Block by
* @returns {Block}
*/
public getBlockByChildNode(childNode: Node): Block {
public getBlockByChildNode(childNode: Node): Block | undefined {
if (!childNode || childNode instanceof Node === false) {
return undefined;
}
/**
* If node is Text TextNode
*/

View file

@ -187,6 +187,13 @@ export default class CrossBlockSelection extends Module {
private onMouseOver = (event: MouseEvent): void => {
const { BlockManager, BlockSelection } = this.Editor;
/**
* Probably, editor is not initialized yet
*/
if (event.relatedTarget === null && event.target === null) {
return;
}
const relatedBlock = BlockManager.getBlockByChildNode(event.relatedTarget as Node) || this.lastSelectedBlock;
const targetBlock = BlockManager.getBlockByChildNode(event.target as Node);

View file

@ -13,7 +13,10 @@ import Popover, { PopoverEvent } from '../../utils/popover';
* HTML Elements that used for BlockSettings
*/
interface BlockSettingsNodes {
wrapper: HTMLElement;
/**
* Block Settings wrapper. Undefined when before "make" method called
*/
wrapper: HTMLElement | undefined;
}
/**

View file

@ -32,12 +32,12 @@ import { BlockHovered } from '../../events/BlockHovered';
* HTML Elements used for Toolbar UI
*/
interface ToolbarNodes {
wrapper: HTMLElement;
content: HTMLElement;
actions: HTMLElement;
wrapper: HTMLElement | undefined;
content: HTMLElement | undefined;
actions: HTMLElement | undefined;
plusButton: HTMLElement;
settingsToggler: HTMLElement;
plusButton: HTMLElement | undefined;
settingsToggler: HTMLElement | undefined;
}
/**
*
@ -316,7 +316,7 @@ export default class Toolbar extends Module<ToolbarNodes> {
return;
}
this.nodes.wrapper.classList.remove(this.CSS.toolbarOpened);
this.nodes.wrapper?.classList.remove(this.CSS.toolbarOpened);
/** Close components */
this.blockActions.hide();

View file

@ -17,16 +17,16 @@ import { IconChevronDown } from '@codexteam/icons';
* Inline Toolbar elements
*/
interface InlineToolbarNodes {
wrapper: HTMLElement;
togglerAndButtonsWrapper: HTMLElement;
buttons: HTMLElement;
conversionToggler: HTMLElement;
conversionTogglerContent: HTMLElement;
wrapper: HTMLElement | undefined;
togglerAndButtonsWrapper: HTMLElement | undefined;
buttons: HTMLElement | undefined;
conversionToggler: HTMLElement | undefined;
conversionTogglerContent: HTMLElement | undefined;
/**
* Zone below the buttons where Tools can create additional actions by 'renderActions()' method
* For example, input for the 'link' tool or textarea for the 'comment' tool
*/
actions: HTMLElement;
actions: HTMLElement | undefined;
}
/**
@ -238,6 +238,10 @@ export default class InlineToolbar extends Module<InlineToolbarNodes> {
* @param {Node} node node to check
*/
public containsNode(node: Node): boolean {
if (this.nodes.wrapper === undefined) {
return false;
}
return this.nodes.wrapper.contains(node);
}

View file

@ -150,12 +150,20 @@ export default class UI extends Module<UINodes> {
*/
if (!readOnlyEnabled) {
/**
* Unbind all events
* Postpone events binding to the next tick to make sure all ui elements are ready
*/
this.enableModuleBindings();
window.requestIdleCallback(() => {
/**
* Bind events for the UI elements
*/
this.enableModuleBindings();
}, {
timeout: 2000,
});
} else {
/**
* Bind events for the UI elements
* Unbind all events
*
*/
this.disableModuleBindings();
}
@ -633,8 +641,8 @@ export default class UI extends Module<UINodes> {
* But allow clicking inside Block Settings.
* Also, do not process clicks on the Block Settings Toggler, because it has own click listener
*/
const isClickedInsideBlockSettings = this.Editor.BlockSettings.nodes.wrapper.contains(target);
const isClickedInsideBlockSettingsToggler = this.Editor.Toolbar.nodes.settingsToggler.contains(target);
const isClickedInsideBlockSettings = this.Editor.BlockSettings.nodes.wrapper?.contains(target);
const isClickedInsideBlockSettingsToggler = this.Editor.Toolbar.nodes.settingsToggler?.contains(target);
const doNotProcess = isClickedInsideBlockSettings || isClickedInsideBlockSettingsToggler;
if (this.Editor.BlockSettings.opened && !doNotProcess) {