mirror of
https://github.com/codex-team/editor.js
synced 2026-03-18 08:29:52 +01:00
Make label an alias for title in tunes item
This commit is contained in:
parent
913ad0c8dc
commit
7534d01e34
14 changed files with 244 additions and 36 deletions
|
|
@ -3,8 +3,9 @@
|
|||
* @classdesc Editor's default tune that moves up selected block
|
||||
* @copyright <CodeX Team> 2018
|
||||
*/
|
||||
import { API, BlockTune, PopoverItem } from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
import { IconCross } from '@codexteam/icons';
|
||||
import { TunesMenuConfig } from '../../../types/tools';
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -34,13 +35,13 @@ export default class DeleteTune implements BlockTune {
|
|||
/**
|
||||
* Tune's appearance in block settings menu
|
||||
*/
|
||||
public render(): PopoverItem {
|
||||
public render(): TunesMenuConfig {
|
||||
return {
|
||||
icon: IconCross,
|
||||
label: this.api.i18n.t('Delete'),
|
||||
title: this.api.i18n.t('Delete'),
|
||||
name: 'delete',
|
||||
confirmation: {
|
||||
label: this.api.i18n.t('Click to delete'),
|
||||
title: this.api.i18n.t('Click to delete'),
|
||||
onActivate: (): void => this.handleClick(),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@
|
|||
* @copyright <CodeX Team> 2018
|
||||
*/
|
||||
|
||||
import { API, BlockTune, PopoverItem } from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
import Popover from '../utils/popover';
|
||||
import { IconChevronDown } from '@codexteam/icons';
|
||||
import { TunesMenuConfig } from '../../../types/tools';
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -44,10 +45,10 @@ export default class MoveDownTune implements BlockTune {
|
|||
/**
|
||||
* Tune's appearance in block settings menu
|
||||
*/
|
||||
public render(): PopoverItem {
|
||||
public render(): TunesMenuConfig {
|
||||
return {
|
||||
icon: IconChevronDown,
|
||||
label: this.api.i18n.t('Move down'),
|
||||
title: this.api.i18n.t('Move down'),
|
||||
onActivate: (item, event): void => this.handleClick(event),
|
||||
name: 'move-down',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
* @classdesc Editor's default tune that moves up selected block
|
||||
* @copyright <CodeX Team> 2018
|
||||
*/
|
||||
import { API, BlockTune, PopoverItem } from '../../../types';
|
||||
import { API, BlockTune } from '../../../types';
|
||||
import Popover from '../../components/utils/popover';
|
||||
import { IconChevronUp } from '@codexteam/icons';
|
||||
import { TunesMenuConfig } from '../../../types/tools';
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -42,10 +43,10 @@ export default class MoveUpTune implements BlockTune {
|
|||
/**
|
||||
* Tune's appearance in block settings menu
|
||||
*/
|
||||
public render(): PopoverItem {
|
||||
public render(): TunesMenuConfig {
|
||||
return {
|
||||
icon: IconChevronUp,
|
||||
label: this.api.i18n.t('Move up'),
|
||||
title: this.api.i18n.t('Move up'),
|
||||
onActivate: (item, e): void => this.handleClick(e),
|
||||
name: 'move-up',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import BlockTune from '../tools/tune';
|
|||
import { BlockTuneData } from '../../../types/block-tunes/block-tune-data';
|
||||
import ToolsCollection from '../tools/collection';
|
||||
import EventsDispatcher from '../utils/events';
|
||||
import { TunesMenuConfigItem } from '../../../types/tools';
|
||||
|
||||
/**
|
||||
* Interface describes Block class constructor argument
|
||||
|
|
@ -646,7 +647,7 @@ export default class Block extends EventsDispatcher<BlockEvents> {
|
|||
*/
|
||||
public getTunes(): [PopoverItem[], HTMLElement] {
|
||||
const customHtmlTunesContainer = document.createElement('div');
|
||||
const tunesItems: PopoverItem[] = [];
|
||||
const tunesItems: TunesMenuConfigItem[] = [];
|
||||
|
||||
/** Tool's tunes: may be defined as return value of optional renderSettings method */
|
||||
const tunesDefinedInTool = typeof this.toolInstance.renderSettings === 'function' ? this.toolInstance.renderSettings() : [];
|
||||
|
|
@ -670,6 +671,31 @@ export default class Block extends EventsDispatcher<BlockEvents> {
|
|||
return [tunesItems, customHtmlTunesContainer];
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Resolves aliases in tunes menu items
|
||||
// *
|
||||
// * @param item - item with resolved aliases
|
||||
// */
|
||||
// private resolveAliases(item: TunesMenuConfigItem, aliases: {[propery: string]: string}): TunesMenuConfigItem {
|
||||
// const result = {} as TunesMenuConfigItem;
|
||||
|
||||
// Object.keys(item).forEach(property => {
|
||||
// result[property] = item[property];
|
||||
|
||||
// const aliasProperty = aliases[property];
|
||||
|
||||
// if (aliasProperty !== undefined) {
|
||||
// result[property] = item[aliasProperty];
|
||||
// }
|
||||
// });
|
||||
|
||||
// if (item.confirmation) {
|
||||
// result.confirmation = this.resolveAliases(item.confirmation, aliases);
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Update current input index with selection anchor node
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import Popover, { PopoverEvent } from '../../utils/popover';
|
|||
import I18n from '../../i18n';
|
||||
import { I18nInternalNS } from '../../i18n/namespace-internal';
|
||||
import Flipper from '../../flipper';
|
||||
import { TunesMenuConfigItem } from '../../../../types/tools';
|
||||
|
||||
/**
|
||||
* HTML Elements that used for BlockSettings
|
||||
|
|
@ -114,7 +115,7 @@ export default class BlockSettings extends Module<BlockSettingsNodes> {
|
|||
searchable: true,
|
||||
filterLabel: I18n.ui(I18nInternalNS.ui.popover, 'Filter'),
|
||||
nothingFoundLabel: I18n.ui(I18nInternalNS.ui.popover, 'Nothing found'),
|
||||
items: tunesItems,
|
||||
items: tunesItems.map(tune => this.resolveAliases(tune, { label: 'title' })),
|
||||
customContent: customHtmlTunesContainer,
|
||||
customContentFlippableItems: this.getControls(customHtmlTunesContainer),
|
||||
scopeElement: this.Editor.API.methods.ui.nodes.redactor,
|
||||
|
|
@ -192,4 +193,29 @@ export default class BlockSettings extends Module<BlockSettingsNodes> {
|
|||
private onOverlayClicked = (): void => {
|
||||
this.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves aliases in tunes menu items
|
||||
*
|
||||
* @param item - item with resolved aliases
|
||||
*/
|
||||
private resolveAliases(item: TunesMenuConfigItem, aliases: {[alias: string]: string}): TunesMenuConfigItem {
|
||||
const result = {} as TunesMenuConfigItem;
|
||||
|
||||
Object.keys(item).forEach(property => {
|
||||
const aliasedProperty = aliases[property];
|
||||
|
||||
if (aliasedProperty !== undefined) {
|
||||
result[aliasedProperty] = item[property];
|
||||
} else {
|
||||
result[property] = item[property];
|
||||
}
|
||||
});
|
||||
|
||||
if (item.confirmation) {
|
||||
result.confirmation = this.resolveAliases(item.confirmation, aliases);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ export default class Toolbox extends EventsDispatcher<ToolboxEvent> {
|
|||
const toPopoverItem = (toolboxItem: ToolboxConfigEntry, tool: BlockTool): PopoverItem => {
|
||||
return {
|
||||
icon: toolboxItem.icon,
|
||||
label: I18n.t(I18nInternalNS.toolNames, toolboxItem.title || _.capitalize(tool.name)),
|
||||
title: I18n.t(I18nInternalNS.toolNames, toolboxItem.title || _.capitalize(tool.name)),
|
||||
name: tool.name,
|
||||
onActivate: (): void => {
|
||||
this.toolButtonActivated(tool.name, toolboxItem.data);
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ export default class Popover extends EventsDispatcher<PopoverEvent> {
|
|||
el.dataset.itemName = item.name;
|
||||
}
|
||||
const label = Dom.make('div', Popover.CSS.itemLabel, {
|
||||
innerHTML: item.label,
|
||||
innerHTML: item.title,
|
||||
});
|
||||
|
||||
el.appendChild(Dom.make('div', Popover.CSS.itemIcon, {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { IconSearch } from '@codexteam/icons';
|
|||
* Item that could be searched
|
||||
*/
|
||||
interface SearchableItem {
|
||||
label: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,7 +145,7 @@ export default class SearchInput {
|
|||
* @param item - item to be checked
|
||||
*/
|
||||
private checkItem(item: SearchableItem): boolean {
|
||||
const text = item.label.toLowerCase();
|
||||
const text = item.title.toLowerCase();
|
||||
const query = this.searchQuery.toLowerCase();
|
||||
|
||||
return text.includes(query);
|
||||
|
|
|
|||
|
|
@ -413,6 +413,87 @@ describe('Editor Tools Api', () => {
|
|||
.get('.ce-popover')
|
||||
.should('contain.text', sampleText);
|
||||
});
|
||||
|
||||
it('should support label alias', () => {
|
||||
/** Tool with single tunes menu entry configured */
|
||||
class TestTool {
|
||||
/** Returns toolbox config as list of entries */
|
||||
public static get toolbox(): ToolboxConfigEntry {
|
||||
return {
|
||||
title: 'Test tool',
|
||||
icon: ICON,
|
||||
};
|
||||
}
|
||||
|
||||
/** Returns configuration for block tunes menu */
|
||||
public renderSettings(): TunesMenuConfig {
|
||||
return [
|
||||
{
|
||||
icon: ICON,
|
||||
name: 'testToolTune1',
|
||||
onActivate: (): void => {},
|
||||
|
||||
// Set text via title property
|
||||
title: 'Test tool tune 1',
|
||||
},
|
||||
{
|
||||
icon: ICON,
|
||||
name: 'testToolTune2',
|
||||
onActivate: (): void => {},
|
||||
|
||||
// Set test via label property
|
||||
label: 'Test tool tune 2',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** Save method stub */
|
||||
public save(): void {}
|
||||
|
||||
/** Renders a block */
|
||||
public render(): HTMLElement {
|
||||
const element = document.createElement('div');
|
||||
|
||||
element.contentEditable = 'true';
|
||||
element.setAttribute('data-name', 'testBlock');
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// Insert test tool block
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.get(`[data-item-name="testTool"]`)
|
||||
.click();
|
||||
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.get('[data-name=testBlock]')
|
||||
.type('some text')
|
||||
.click();
|
||||
|
||||
// Open block tunes
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.get('.ce-toolbar__settings-btn')
|
||||
.click();
|
||||
|
||||
// Expect both tunes to have correct text
|
||||
cy.get('[data-item-name=testToolTune1]').contains('Test tool tune 1');
|
||||
cy.get('[data-item-name=testToolTune2]').contains('Test tool tune 2');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ describe('Editor Tunes Api', () => {
|
|||
public render(): TunesMenuConfig {
|
||||
return {
|
||||
icon: 'ICON',
|
||||
label: 'Test tune',
|
||||
title: 'Test tune',
|
||||
name: 'testTune',
|
||||
|
||||
onActivate: (): void => { },
|
||||
|
|
@ -54,13 +54,13 @@ describe('Editor Tunes Api', () => {
|
|||
return [
|
||||
{
|
||||
icon: 'ICON1',
|
||||
label: 'Tune entry 1',
|
||||
title: 'Tune entry 1',
|
||||
name: 'testTune1',
|
||||
|
||||
onActivate: (): void => { },
|
||||
}, {
|
||||
icon: 'ICON2',
|
||||
label: 'Tune entry 2',
|
||||
title: 'Tune entry 2',
|
||||
name: 'testTune2',
|
||||
|
||||
onActivate: (): void => { },
|
||||
|
|
@ -133,4 +133,53 @@ describe('Editor Tunes Api', () => {
|
|||
.get('.ce-popover')
|
||||
.should('contain.text', sampleText);
|
||||
});
|
||||
|
||||
it('should support label alias', () => {
|
||||
/** Test tune that should appear be rendered in block tunes menu */
|
||||
class TestTune {
|
||||
/** Set Tool is Tune */
|
||||
public static readonly isTune = true;
|
||||
|
||||
/** Tune's appearance in block settings menu */
|
||||
public render(): TunesMenuConfig {
|
||||
return [
|
||||
{
|
||||
icon: 'ICON1',
|
||||
name: 'testTune1',
|
||||
onActivate: (): void => { },
|
||||
|
||||
// Set text via title property
|
||||
title: 'Tune entry 1',
|
||||
}, {
|
||||
icon: 'ICON2',
|
||||
name: 'testTune2',
|
||||
onActivate: (): void => { },
|
||||
|
||||
// Set text via label property
|
||||
label: 'Tune entry 2',
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
cy.createEditor({
|
||||
tools: {
|
||||
testTune: TestTune,
|
||||
},
|
||||
tunes: [ 'testTune' ],
|
||||
}).as('editorInstance');
|
||||
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.get('div.ce-block')
|
||||
.type('some text')
|
||||
.click();
|
||||
|
||||
cy.get('[data-cy=editorjs]')
|
||||
.get('.ce-toolbar__settings-btn')
|
||||
.click();
|
||||
|
||||
/** Check both tunes have correct text */
|
||||
cy.get('[data-item-name=testTune1]').contains('Tune entry 1');
|
||||
cy.get('[data-item-name=testTune2]').contains('Tune entry 2');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class SomePlugin {
|
|||
public static get toolbox(): PopoverItem {
|
||||
return {
|
||||
icon: '₷',
|
||||
label: 'Some tool',
|
||||
title: 'Some tool',
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
onActivate: (): void => {},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { PopoverItem } from '../../../../types';
|
|||
describe('Popover', () => {
|
||||
it('should support confirmation chains', () => {
|
||||
const actionIcon = 'Icon 1';
|
||||
const actionLabel = 'Action';
|
||||
const actionTitle = 'Action';
|
||||
const confirmActionIcon = 'Icon 2';
|
||||
const confirmActionLabel = 'Confirm action';
|
||||
const confirmActionTitle = 'Confirm action';
|
||||
|
||||
/**
|
||||
* Confirmation is moved to separate variable to be able to test it's callback execution.
|
||||
|
|
@ -16,14 +16,14 @@ describe('Popover', () => {
|
|||
*/
|
||||
const confirmation = {
|
||||
icon: confirmActionIcon,
|
||||
label: confirmActionLabel,
|
||||
title: confirmActionTitle,
|
||||
onActivate: cy.stub(),
|
||||
};
|
||||
|
||||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: actionIcon,
|
||||
label: actionLabel,
|
||||
title: actionTitle,
|
||||
name: 'testItem',
|
||||
confirmation,
|
||||
},
|
||||
|
|
@ -45,7 +45,7 @@ describe('Popover', () => {
|
|||
|
||||
cy.get('[data-item-name=testItem]')
|
||||
.get('.ce-popover__item-label')
|
||||
.should('have.text', actionLabel);
|
||||
.should('have.text', actionTitle);
|
||||
|
||||
// First click on item
|
||||
cy.get('[data-item-name=testItem]').click();
|
||||
|
|
@ -58,7 +58,7 @@ describe('Popover', () => {
|
|||
// Check label has changed
|
||||
cy.get('[data-item-name=testItem]')
|
||||
.get('.ce-popover__item-label')
|
||||
.should('have.text', confirmActionLabel);
|
||||
.should('have.text', confirmActionTitle);
|
||||
|
||||
// Second click
|
||||
cy.get('[data-item-name=testItem]')
|
||||
|
|
@ -74,7 +74,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon',
|
||||
label: 'Label',
|
||||
title: 'Title',
|
||||
isActive: true,
|
||||
name: 'testItem',
|
||||
onActivate: (): void => {},
|
||||
|
|
@ -101,7 +101,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon',
|
||||
label: 'Label',
|
||||
title: 'Title',
|
||||
isDisabled: true,
|
||||
name: 'testItem',
|
||||
onActivate: cy.stub(),
|
||||
|
|
@ -133,7 +133,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon',
|
||||
label: 'Label',
|
||||
title: 'Title',
|
||||
closeOnActivate: true,
|
||||
name: 'testItem',
|
||||
onActivate: (): void => {},
|
||||
|
|
@ -163,7 +163,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon',
|
||||
label: 'Label',
|
||||
title: 'Title',
|
||||
toggle: true,
|
||||
name: 'testItem',
|
||||
onActivate: (): void => {},
|
||||
|
|
@ -190,7 +190,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon 1',
|
||||
label: 'Label 1',
|
||||
title: 'Title 1',
|
||||
toggle: 'group-name',
|
||||
name: 'testItem1',
|
||||
isActive: true,
|
||||
|
|
@ -198,7 +198,7 @@ describe('Popover', () => {
|
|||
},
|
||||
{
|
||||
icon: 'Icon 2',
|
||||
label: 'Label 2',
|
||||
title: 'Title 2',
|
||||
toggle: 'group-name',
|
||||
name: 'testItem2',
|
||||
onActivate: (): void => {},
|
||||
|
|
@ -238,7 +238,7 @@ describe('Popover', () => {
|
|||
const items: PopoverItem[] = [
|
||||
{
|
||||
icon: 'Icon',
|
||||
label: 'Label',
|
||||
title: 'Title',
|
||||
toggle: 'key',
|
||||
name: 'testItem',
|
||||
onActivate: (): void => {},
|
||||
|
|
|
|||
4
types/configs/popover.d.ts
vendored
4
types/configs/popover.d.ts
vendored
|
|
@ -5,7 +5,7 @@ interface PopoverItemBase {
|
|||
/**
|
||||
* Displayed text
|
||||
*/
|
||||
label: string;
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* Item icon to be appeared near a title
|
||||
|
|
@ -54,7 +54,7 @@ export interface PopoverItemWithConfirmation extends PopoverItemBase {
|
|||
* Popover item parameters that should be applied on item activation.
|
||||
* May be used to ask user for confirmation before executing popover item activation handler.
|
||||
*/
|
||||
confirmation: Partial<PopoverItem>;
|
||||
confirmation: PopoverItem;
|
||||
|
||||
onActivate?: never;
|
||||
}
|
||||
|
|
|
|||
25
types/tools/tool-settings.d.ts
vendored
25
types/tools/tool-settings.d.ts
vendored
|
|
@ -28,11 +28,34 @@ export interface ToolboxConfigEntry {
|
|||
data?: BlockToolData
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents single Tunes Menu item
|
||||
*/
|
||||
export type TunesMenuConfigItem = PopoverItem & {
|
||||
/**
|
||||
* Tune displayed text.
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* Tune displayed text.
|
||||
* Alias for title property
|
||||
*/
|
||||
label?: string
|
||||
|
||||
/**
|
||||
* Menu item parameters that should be applied on item activation.
|
||||
* May be used to ask user for confirmation before executing menu item activation handler.
|
||||
*/
|
||||
confirmation?: TunesMenuConfigItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool may specify its tunes configuration
|
||||
* that can contain either one or multiple entries
|
||||
*/
|
||||
export type TunesMenuConfig = PopoverItem | PopoverItem[];
|
||||
export type TunesMenuConfig = TunesMenuConfigItem | TunesMenuConfigItem[];
|
||||
|
||||
/**
|
||||
* Object passed to the Tool's constructor by {@link EditorConfig#tools}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue