mirror of
https://github.com/codex-team/editor.js
synced 2024-05-02 22:53:23 +02:00
fix(toolbox): shortcuts appearance fixed, icons became optional (#2188)
* fix(toolbox): shortcuts appearing fixed, icons became optional * rm only from test * Update tools.spec.ts * rm useless tests * Update CHANGELOG.md
This commit is contained in:
parent
04118b2d6e
commit
1a72d2153b
|
@ -14,8 +14,10 @@
|
||||||
- `Fix` — If a Tool specifies some tags to substitute on paste, all attributes of that tags will be removed before passing them to the tool. Possible XSS vulnerability fixed.
|
- `Fix` — If a Tool specifies some tags to substitute on paste, all attributes of that tags will be removed before passing them to the tool. Possible XSS vulnerability fixed.
|
||||||
- `Fix` — Pasting from Microsoft Word to Chrome (Mac OS) fixed. Now if there are no image-tools connected, regular text content will be pasted.
|
- `Fix` — Pasting from Microsoft Word to Chrome (Mac OS) fixed. Now if there are no image-tools connected, regular text content will be pasted.
|
||||||
- `Fix` — Workaround for the HTMLJanitor bug with Tables (https://github.com/guardian/html-janitor/issues/3) added
|
- `Fix` — Workaround for the HTMLJanitor bug with Tables (https://github.com/guardian/html-janitor/issues/3) added
|
||||||
|
- `Fix` — Toolbox shortcuts appearance and execution fixed [#2112](https://github.com/codex-team/editor.js/issues/2112)
|
||||||
- `Improvement` — *Tools API* — `pasteConfig().tags` now support sanitizing configuration. It allows you to leave some explicitly specified attributes for pasted content.
|
- `Improvement` — *Tools API* — `pasteConfig().tags` now support sanitizing configuration. It allows you to leave some explicitly specified attributes for pasted content.
|
||||||
- `Improvement` — *CodeStyle* — [CodeX ESLint Config](https://github.com/codex-team/eslint-config) has bee updated. All ESLint/Spelling issues resolved
|
- `Improvement` — *CodeStyle* — [CodeX ESLint Config](https://github.com/codex-team/eslint-config) has bee updated. All ESLint/Spelling issues resolved
|
||||||
|
- `Improvement` — *ToolsAPI* — The `icon` property of the `toolbox` getter became optional.
|
||||||
|
|
||||||
### 2.25.0
|
### 2.25.0
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ Due to that API changes: tool's `toolbox` getter now can return either a single
|
||||||
|
|
||||||
### 2.24.4
|
### 2.24.4
|
||||||
|
|
||||||
- `Fix` — Keyboard selection by word [2045](https://github.com/codex-team/editor.js/issues/2045)
|
- `Fix` — Keyboard selection by word [#2045](https://github.com/codex-team/editor.js/issues/2045)
|
||||||
|
|
||||||
### 2.24.3
|
### 2.24.3
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
/**
|
/**
|
||||||
* Popover instance. There is a util for vertical lists.
|
* Popover instance. There is a util for vertical lists.
|
||||||
*/
|
*/
|
||||||
private popover: Popover;
|
private popover: Popover | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of Tools available. Some of them will be shown in the Toolbox
|
* List of Tools available. Some of them will be shown in the Toolbox
|
||||||
|
@ -86,7 +86,7 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
* Current module HTML Elements
|
* Current module HTML Elements
|
||||||
*/
|
*/
|
||||||
private nodes: {
|
private nodes: {
|
||||||
toolbox: HTMLElement;
|
toolbox: HTMLElement | null;
|
||||||
} = {
|
} = {
|
||||||
toolbox: null,
|
toolbox: null,
|
||||||
};
|
};
|
||||||
|
@ -102,11 +102,6 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Id of listener added used to remove it on destroy()
|
|
||||||
*/
|
|
||||||
private clickListenerId: string = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toolbox constructor
|
* Toolbox constructor
|
||||||
*
|
*
|
||||||
|
@ -150,8 +145,8 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
/**
|
/**
|
||||||
* Returns true if the Toolbox has the Flipper activated and the Flipper has selected button
|
* Returns true if the Toolbox has the Flipper activated and the Flipper has selected button
|
||||||
*/
|
*/
|
||||||
public hasFocus(): boolean {
|
public hasFocus(): boolean | undefined {
|
||||||
return this.popover.hasFocus();
|
return this.popover?.hasFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,10 +160,8 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
this.nodes.toolbox = null;
|
this.nodes.toolbox = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.api.listeners.offById(this.clickListenerId);
|
|
||||||
|
|
||||||
this.removeAllShortcuts();
|
this.removeAllShortcuts();
|
||||||
this.popover.off(PopoverEvent.OverlayClicked, this.onOverlayClicked);
|
this.popover?.off(PopoverEvent.OverlayClicked, this.onOverlayClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,7 +182,7 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.popover.show();
|
this.popover?.show();
|
||||||
this.opened = true;
|
this.opened = true;
|
||||||
this.emit(ToolboxEvent.Opened);
|
this.emit(ToolboxEvent.Opened);
|
||||||
}
|
}
|
||||||
|
@ -198,7 +191,7 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
* Close Toolbox
|
* Close Toolbox
|
||||||
*/
|
*/
|
||||||
public close(): void {
|
public close(): void {
|
||||||
this.popover.hide();
|
this.popover?.hide();
|
||||||
this.opened = false;
|
this.opened = false;
|
||||||
this.emit(ToolboxEvent.Closed);
|
this.emit(ToolboxEvent.Closed);
|
||||||
}
|
}
|
||||||
|
@ -226,24 +219,17 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
*/
|
*/
|
||||||
@_.cacheable
|
@_.cacheable
|
||||||
private get toolsToBeDisplayed(): BlockTool[] {
|
private get toolsToBeDisplayed(): BlockTool[] {
|
||||||
return Array
|
const result: BlockTool[] = [];
|
||||||
.from(this.tools.values())
|
|
||||||
.reduce((result, tool) => {
|
this.tools.forEach((tool) => {
|
||||||
const toolToolboxSettings = tool.toolbox;
|
const toolToolboxSettings = tool.toolbox;
|
||||||
|
|
||||||
if (toolToolboxSettings) {
|
if (toolToolboxSettings) {
|
||||||
const validToolboxSettings = toolToolboxSettings.filter(item => {
|
result.push(tool);
|
||||||
return this.areToolboxSettingsValid(item, tool.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
result.push({
|
|
||||||
...tool,
|
|
||||||
toolbox: validToolboxSettings,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, []);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,12 +253,12 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.toolsToBeDisplayed
|
return this.toolsToBeDisplayed
|
||||||
.reduce((result, tool) => {
|
.reduce<PopoverItem[]>((result, tool) => {
|
||||||
if (Array.isArray(tool.toolbox)) {
|
if (Array.isArray(tool.toolbox)) {
|
||||||
tool.toolbox.forEach(item => {
|
tool.toolbox.forEach(item => {
|
||||||
result.push(toPopoverItem(item, tool));
|
result.push(toPopoverItem(item, tool));
|
||||||
});
|
});
|
||||||
} else {
|
} else if (tool.toolbox !== undefined) {
|
||||||
result.push(toPopoverItem(tool.toolbox, tool));
|
result.push(toPopoverItem(tool.toolbox, tool));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,29 +266,6 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates tool's toolbox settings
|
|
||||||
*
|
|
||||||
* @param toolToolboxSettings - item to validate
|
|
||||||
* @param toolName - name of the tool used in console warning if item is not valid
|
|
||||||
*/
|
|
||||||
private areToolboxSettingsValid(toolToolboxSettings: ToolboxConfigEntry, toolName: string): boolean {
|
|
||||||
/**
|
|
||||||
* Skip tools that don't pass 'toolbox' property
|
|
||||||
*/
|
|
||||||
if (!toolToolboxSettings) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toolToolboxSettings && !toolToolboxSettings.icon) {
|
|
||||||
_.log('Toolbar icon is missed. Tool %o skipped', 'warn', toolName);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate all tools and enable theirs shortcuts if specified
|
* Iterate all tools and enable theirs shortcuts if specified
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -437,11 +437,9 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
|
||||||
innerHTML: item.label,
|
innerHTML: item.label,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (item.icon) {
|
|
||||||
el.appendChild(Dom.make('div', Popover.CSS.itemIcon, {
|
el.appendChild(Dom.make('div', Popover.CSS.itemIcon, {
|
||||||
innerHTML: item.icon,
|
innerHTML: item.icon || item.name.substring(0, 1).toUpperCase(),
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
|
|
||||||
el.appendChild(label);
|
el.appendChild(label);
|
||||||
|
|
||||||
|
|
|
@ -192,83 +192,6 @@ describe('Editor Tools Api', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display tool in toolbox if the tool has single toolbox entry configured and it has icon missing', () => {
|
|
||||||
/**
|
|
||||||
* Tool with one of the toolbox entries with icon missing
|
|
||||||
*/
|
|
||||||
class TestTool {
|
|
||||||
/**
|
|
||||||
* Returns toolbox config as list of entries one of which has missing icon
|
|
||||||
*/
|
|
||||||
public static get toolbox(): ToolboxConfig {
|
|
||||||
return {
|
|
||||||
title: 'Entry 2',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cy.createEditor({
|
|
||||||
tools: {
|
|
||||||
testTool: TestTool,
|
|
||||||
},
|
|
||||||
}).as('editorInstance');
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-block')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-toolbar__plus')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-popover__item[data-item-name=testTool]')
|
|
||||||
.should('not.exist');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip toolbox entries that have no icon', () => {
|
|
||||||
const skippedEntryTitle = 'Entry 2';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tool with one of the toolbox entries with icon missing
|
|
||||||
*/
|
|
||||||
class TestTool {
|
|
||||||
/**
|
|
||||||
* Returns toolbox config as list of entries one of which has missing icon
|
|
||||||
*/
|
|
||||||
public static get toolbox(): ToolboxConfig {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: 'Entry 1',
|
|
||||||
icon: ICON,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: skippedEntryTitle,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cy.createEditor({
|
|
||||||
tools: {
|
|
||||||
testTool: TestTool,
|
|
||||||
},
|
|
||||||
}).as('editorInstance');
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-block')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-toolbar__plus')
|
|
||||||
.click();
|
|
||||||
|
|
||||||
cy.get('[data-cy=editorjs]')
|
|
||||||
.get('div.ce-popover__item[data-item-name=testTool]')
|
|
||||||
.should('have.length', 1)
|
|
||||||
.should('not.contain', skippedEntryTitle);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context('Tunes — renderSettings()', () => {
|
context('Tunes — renderSettings()', () => {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import Header from '@editorjs/header';
|
import Header from '@editorjs/header';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
|
||||||
describe.only('Block ids', () => {
|
describe('Block ids', () => {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.createEditor({
|
cy.createEditor({
|
||||||
tools: {
|
tools: {
|
||||||
|
|
10
types/configs/popover.d.ts
vendored
10
types/configs/popover.d.ts
vendored
|
@ -2,16 +2,16 @@
|
||||||
* Common parameters for both types of popover items: with or without confirmation
|
* Common parameters for both types of popover items: with or without confirmation
|
||||||
*/
|
*/
|
||||||
interface PopoverItemBase {
|
interface PopoverItemBase {
|
||||||
/**
|
|
||||||
* Item icon to be appeared near a title
|
|
||||||
*/
|
|
||||||
icon: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displayed text
|
* Displayed text
|
||||||
*/
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item icon to be appeared near a title
|
||||||
|
*/
|
||||||
|
icon?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional displayed text
|
* Additional displayed text
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue