From cd5989ec00268a8f6510847da5597f37d0eb0770 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Wed, 20 May 2026 16:25:06 +0400 Subject: [PATCH] Refactor OpenTraitManager --- packages/core/src/commands/registry.ts | 10 ++- .../src/commands/view/OpenTraitManager.ts | 83 +++++++++++-------- .../specs/commands/view/OpenTraitManager.ts | 27 ++++++ 3 files changed, 82 insertions(+), 38 deletions(-) create mode 100644 packages/core/test/specs/commands/view/OpenTraitManager.ts diff --git a/packages/core/src/commands/registry.ts b/packages/core/src/commands/registry.ts index 827d19b3e..4f8fc503d 100644 --- a/packages/core/src/commands/registry.ts +++ b/packages/core/src/commands/registry.ts @@ -19,6 +19,10 @@ import type { OpenStyleManagerCommandRegistryRun, OpenStyleManagerCommandRegistryStop, } from './view/OpenStyleManager'; +import type { + OpenTraitManagerCommandRegistryRun, + OpenTraitManagerCommandRegistryStop, +} from './view/OpenTraitManager'; type CommandRegistryHandler = (...args: any[]) => any; type CommandRegistryEntry = TId extends keyof TRegistry @@ -37,7 +41,8 @@ export interface CommandRegistryRun CanvasClearCommandRegistryRun, ExportTemplateCommandRegistryRun, OpenLayersCommandRegistryRun, - OpenStyleManagerCommandRegistryRun {} + OpenStyleManagerCommandRegistryRun, + OpenTraitManagerCommandRegistryRun {} export interface CommandRegistryStop extends FullscreenCommandRegistryStop, @@ -46,7 +51,8 @@ export interface CommandRegistryStop CanvasMoveCommandRegistryStop, ExportTemplateCommandRegistryStop, OpenLayersCommandRegistryStop, - OpenStyleManagerCommandRegistryStop {} + OpenStyleManagerCommandRegistryStop, + OpenTraitManagerCommandRegistryStop {} export type CommandRunKnownId = Extract; export type CommandStopKnownId = Extract; diff --git a/packages/core/src/commands/view/OpenTraitManager.ts b/packages/core/src/commands/view/OpenTraitManager.ts index 1076f57ff..2444e0459 100644 --- a/packages/core/src/commands/view/OpenTraitManager.ts +++ b/packages/core/src/commands/view/OpenTraitManager.ts @@ -1,71 +1,82 @@ -import { CommandObject } from './CommandAbstract'; import { $ } from '../../common'; import { ComponentsEvents } from '../../dom_components/types'; +import Editor from '../../editor'; +import type { CommandPublicFnFromHandler } from '../registryHelpers'; +import CommandAbstract from './CommandAbstract'; -export default { - run(editor, sender) { +export interface OpenTraitManagerCommandRegistryRun { + 'core:open-traits': CommandPublicFnFromHandler; + 'open-tm': CommandPublicFnFromHandler; +} + +export interface OpenTraitManagerCommandRegistryStop { + 'core:open-traits': CommandPublicFnFromHandler; + 'open-tm': CommandPublicFnFromHandler; +} + +export default class CommandOpenTraitManager extends CommandAbstract { + sender?: any; + target?: any; + $cn?: any; + $cn2?: any; + $header?: any; + + run(editor: Editor, sender: any) { this.sender = sender; const em = editor.getModel(); - const config = editor.Config; const pfx = config.stylePrefix; const tm = editor.TraitManager; const confTm = tm.getConfig(); - let panelC; if (confTm.appendTo) return; if (!this.$cn) { - this.$cn = $('
'); - this.$cn2 = $('
'); - this.$cn.append(this.$cn2); + const $cn = $('
'); + const $cn2 = $('
'); + this.$cn = $cn; + this.$cn2 = $cn2; + $cn.append($cn2); this.$header = $('
').append(`
${em.t('traitManager.empty')}
`); - this.$cn.append(this.$header); + $cn.append(this.$header); if (confTm.custom) { - tm.__trgCustom({ container: this.$cn2.get(0) }); - } else { - this.$cn2.append(`
${em.t('traitManager.label')}
`); - this.$cn2.append(tm.render()); - } - - var panels = editor.Panels; - - if (!panels.getPanel('views-container')) { - // @ts-ignore - panelC = panels.addPanel({ id: 'views-container' }); + tm.__trgCustom({ container: $cn2.get(0) }); } else { - panelC = panels.getPanel('views-container'); + $cn2.append(`
${em.t('traitManager.label')}
`); + $cn2.append(tm.render()); } - panelC?.set('appendContent', this.$cn.get(0)).trigger('change:appendContent'); + const panels = editor.Panels; + const panel = panels.getPanel('views-container') || panels.addPanel({ id: 'views-container' }); + panel?.set('appendContent', $cn.get(0)).trigger('change:appendContent'); - this.target = editor.getModel(); + this.target = em; this.listenTo(this.target, ComponentsEvents.toggled, this.toggleTm); } this.toggleTm(); - }, + } /** * Toggle Trait Manager visibility * @private */ toggleTm() { - const sender = this.sender; - if (sender && sender.get && !sender.get('active')) return; + const { sender, target, $cn2, $header } = this; + if ((sender && sender.get && !sender.get('active')) || !target) return; - if (this.target.getSelectedAll().length === 1) { - this.$cn2.show(); - this.$header.hide(); + if (target.getSelectedAll().length === 1) { + $cn2?.show(); + $header?.hide(); } else { - this.$cn2.hide(); - this.$header.show(); + $cn2?.hide(); + $header?.show(); } - }, + } stop() { - this.$cn2 && this.$cn2.hide(); - this.$header && this.$header.hide(); - }, -} as CommandObject<{}, { [k: string]: any }>; + this.$cn2?.hide(); + this.$header?.hide(); + } +} diff --git a/packages/core/test/specs/commands/view/OpenTraitManager.ts b/packages/core/test/specs/commands/view/OpenTraitManager.ts new file mode 100644 index 000000000..8502413d8 --- /dev/null +++ b/packages/core/test/specs/commands/view/OpenTraitManager.ts @@ -0,0 +1,27 @@ +import OpenTraitManager from '../../../../src/commands/view/OpenTraitManager'; + +describe('OpenTraitManager command', () => { + test('toggleTm should show content when a single target is selected', () => { + const command = new OpenTraitManager({}); + command.sender = { get: jest.fn(() => true) }; + command.target = { getSelectedAll: jest.fn(() => [{}]) }; + command.$cn2 = { show: jest.fn(), hide: jest.fn() }; + command.$header = { show: jest.fn(), hide: jest.fn() }; + + command.toggleTm(); + + expect(command.$cn2.show).toHaveBeenCalledTimes(1); + expect(command.$header.hide).toHaveBeenCalledTimes(1); + }); + + test('stop should hide content and header', () => { + const command = new OpenTraitManager({}); + command.$cn2 = { hide: jest.fn() }; + command.$header = { hide: jest.fn() }; + + command.stop(); + + expect(command.$cn2.hide).toHaveBeenCalledTimes(1); + expect(command.$header.hide).toHaveBeenCalledTimes(1); + }); +});