Make label an alias for title in tunes item

This commit is contained in:
Tanya Fomina 2022-12-02 23:39:05 +04:00
commit 7534d01e34
14 changed files with 244 additions and 36 deletions

View file

@ -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(),
},
};

View file

@ -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',
};

View file

@ -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',
};

View file

@ -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
*/

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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, {

View file

@ -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);

View file

@ -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');
});
});
/**

View file

@ -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');
});
});

View file

@ -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 => {},
};

View file

@ -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 => {},

View file

@ -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;
}

View file

@ -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}