Browse Source

Refactor SelectComponent

typed-command-runs
Artur Arseniev 5 months ago
parent
commit
16c2162c82
  1. 3
      packages/core/src/commands/registry.ts
  2. 13
      packages/core/src/commands/view/MoveComponent.ts
  3. 304
      packages/core/src/commands/view/SelectComponent.ts
  4. 30
      packages/core/test/specs/commands/view/SelectComponent.ts

3
packages/core/src/commands/registry.ts

@ -18,6 +18,7 @@ import type { OpenAssetsCommandRegistryRun, OpenAssetsCommandRegistryStop } from
import type { OpenLayersCommandRegistryRun, OpenLayersCommandRegistryStop } from './view/OpenLayers'; import type { OpenLayersCommandRegistryRun, OpenLayersCommandRegistryStop } from './view/OpenLayers';
import type { OpenBlocksCommandRegistryRun, OpenBlocksCommandRegistryStop } from './view/OpenBlocks'; import type { OpenBlocksCommandRegistryRun, OpenBlocksCommandRegistryStop } from './view/OpenBlocks';
import type { MoveComponentCommandRegistryRun, MoveComponentCommandRegistryStop } from './view/MoveComponent'; import type { MoveComponentCommandRegistryRun, MoveComponentCommandRegistryStop } from './view/MoveComponent';
import type { SelectComponentCommandRegistryRun, SelectComponentCommandRegistryStop } from './view/SelectComponent';
import type { ShowOffsetCommandRegistryRun, ShowOffsetCommandRegistryStop } from './view/ShowOffset'; import type { ShowOffsetCommandRegistryRun, ShowOffsetCommandRegistryStop } from './view/ShowOffset';
import type { SwitchVisibilityCommandRegistryRun, SwitchVisibilityCommandRegistryStop } from './view/SwitchVisibility'; import type { SwitchVisibilityCommandRegistryRun, SwitchVisibilityCommandRegistryStop } from './view/SwitchVisibility';
import type { import type {
@ -51,6 +52,7 @@ export interface CommandRegistryRun
OpenLayersCommandRegistryRun, OpenLayersCommandRegistryRun,
OpenStyleManagerCommandRegistryRun, OpenStyleManagerCommandRegistryRun,
OpenTraitManagerCommandRegistryRun, OpenTraitManagerCommandRegistryRun,
SelectComponentCommandRegistryRun,
ShowOffsetCommandRegistryRun, ShowOffsetCommandRegistryRun,
SwitchVisibilityCommandRegistryRun {} SwitchVisibilityCommandRegistryRun {}
@ -66,6 +68,7 @@ export interface CommandRegistryStop
OpenLayersCommandRegistryStop, OpenLayersCommandRegistryStop,
OpenStyleManagerCommandRegistryStop, OpenStyleManagerCommandRegistryStop,
OpenTraitManagerCommandRegistryStop, OpenTraitManagerCommandRegistryStop,
SelectComponentCommandRegistryStop,
ShowOffsetCommandRegistryStop, ShowOffsetCommandRegistryStop,
SwitchVisibilityCommandRegistryStop {} SwitchVisibilityCommandRegistryStop {}

13
packages/core/src/commands/view/MoveComponent.ts

@ -7,6 +7,8 @@ import CommandAbstract from './CommandAbstract';
import SelectComponent from './SelectComponent'; import SelectComponent from './SelectComponent';
import SelectPosition from './SelectPosition'; import SelectPosition from './SelectPosition';
const SelectComponentProto = SelectComponent.prototype as any;
export interface MoveComponentCommandRegistryRun { export interface MoveComponentCommandRegistryRun {
'core:component-move': CommandPublicFnFromHandler<CommandMoveComponent['run']>; 'core:component-move': CommandPublicFnFromHandler<CommandMoveComponent['run']>;
'move-comp': CommandPublicFnFromHandler<CommandMoveComponent['run']>; 'move-comp': CommandPublicFnFromHandler<CommandMoveComponent['run']>;
@ -21,7 +23,7 @@ export default class CommandMoveComponent extends CommandAbstract {
[key: string]: any; [key: string]: any;
init(o: any) { init(o: any) {
(SelectComponent.init as any).apply(this, arguments as any); SelectComponentProto.init.apply(this, arguments as any);
bindAll(this, 'initSorter', 'rollback', 'onEndMove'); bindAll(this, 'initSorter', 'rollback', 'onEndMove');
this.opt = o; this.opt = o;
this.hoverClass = `${this.ppfx}highlighter-warning`; this.hoverClass = `${this.ppfx}highlighter-warning`;
@ -34,7 +36,7 @@ export default class CommandMoveComponent extends CommandAbstract {
} }
enable(...args: any[]) { enable(...args: any[]) {
SelectComponent.enable.apply(this, args); SelectComponentProto.enable.apply(this, args);
this.getBadgeEl().addClass(this.badgeClass); this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass); this.getHighlighterEl().addClass(this.hoverClass);
const wp = this.$wrapper; const wp = this.$wrapper;
@ -167,7 +169,7 @@ export default class CommandMoveComponent extends CommandAbstract {
} }
stop(...args: any[]) { stop(...args: any[]) {
(SelectComponent.stop as any).apply(this, args); SelectComponentProto.stop.apply(this, args);
this.getBadgeEl().removeClass(this.badgeClass); this.getBadgeEl().removeClass(this.badgeClass);
this.getHighlighterEl().removeClass(this.hoverClass); this.getHighlighterEl().removeClass(this.hoverClass);
const wp = this.$wrapper; const wp = this.$wrapper;
@ -177,9 +179,10 @@ export default class CommandMoveComponent extends CommandAbstract {
[ [
SelectPosition as Record<string, unknown>, SelectPosition as Record<string, unknown>,
SelectComponent as Record<string, unknown>, SelectComponentProto as Record<string, unknown>,
].forEach((source) => { ].forEach((source) => {
Object.keys(source).forEach((key) => { Object.getOwnPropertyNames(source).forEach((key) => {
if (key === 'constructor') return;
if (!(key in CommandMoveComponent.prototype)) { if (!(key in CommandMoveComponent.prototype)) {
(CommandMoveComponent.prototype as Record<string, unknown>)[key] = source[key]; (CommandMoveComponent.prototype as Record<string, unknown>)[key] = source[key];
} }

304
packages/core/src/commands/view/SelectComponent.ts

@ -7,9 +7,21 @@ import { ComponentResizeInitEventData, ComponentsEvents } from '../../dom_compon
import ToolbarView from '../../dom_components/view/ToolbarView'; import ToolbarView from '../../dom_components/view/ToolbarView';
import { isDoc, isTaggableNode, isVisible, off, on } from '../../utils/dom'; import { isDoc, isTaggableNode, isVisible, off, on } from '../../utils/dom';
import { getComponentModel, getComponentView, hasWin, isObject } from '../../utils/mixins'; import { getComponentModel, getComponentView, hasWin, isObject } from '../../utils/mixins';
import { CommandObject } from './CommandAbstract'; import type { CommandPublicFnFromHandler } from '../registryHelpers';
import CommandAbstract from './CommandAbstract';
let showOffsets: boolean; let showOffsets: boolean;
export interface SelectComponentCommandRegistryRun {
'core:component-select': CommandPublicFnFromHandler<CommandSelectComponent['run']>;
'select-comp': CommandPublicFnFromHandler<CommandSelectComponent['run']>;
}
export interface SelectComponentCommandRegistryStop {
'core:component-select': CommandPublicFnFromHandler<CommandSelectComponent['stop']>;
'select-comp': CommandPublicFnFromHandler<CommandSelectComponent['stop']>;
}
/** /**
* This command is responsible for show selecting components and displaying * This command is responsible for show selecting components and displaying
* all the necessary tools around (component toolbar, badge, highlight box, etc.) * all the necessary tools around (component toolbar, badge, highlight box, etc.)
@ -28,12 +40,21 @@ let showOffsets: boolean;
* you can see stuff like the highlight box, badge, margins/paddings offsets, etc. * you can see stuff like the highlight box, badge, margins/paddings offsets, etc.
* so those elements are inside the Local Tools box * so those elements are inside the Local Tools box
* *
*
*/ */
export default { export default class CommandSelectComponent extends CommandAbstract {
activeResizer: false, [key: string]: any;
activeResizer = false;
init() { init() {
this._upToolbar = debounce(() => {
this.updateToolsGlobal({ force: 1 });
}, 0);
this.updateAttached = debounce(() => {
this.updateGlobalPos();
}, 0);
this.onContainerChange = debounce(() => {
this.em.refreshCanvas();
}, 150);
this.onSelect = debounce(this.onSelect, 0); this.onSelect = debounce(this.onSelect, 0);
bindAll( bindAll(
this, this,
@ -46,22 +67,22 @@ export default {
'onFrameUpdated', 'onFrameUpdated',
'onContainerChange', 'onContainerChange',
); );
}, }
enable() { enable() {
this.frameOff = this.canvasOff = this.adjScroll = null; this.frameOff = this.canvasOff = this.adjScroll = null;
this.startSelectComponent(); this.startSelectComponent();
showOffsets = true; showOffsets = true;
}, }
/** /**
* Start select component event * Start select component event
* @private * @private
* */ * */
startSelectComponent() { startSelectComponent() {
this.toggleSelectComponent(1); this.toggleSelectComponent(true);
this.em.getSelected() && this.onSelect(); this.em.getSelected() && this.onSelect();
}, }
/** /**
* Stop select component event * Stop select component event
@ -69,17 +90,17 @@ export default {
* */ * */
stopSelectComponent() { stopSelectComponent() {
this.toggleSelectComponent(); this.toggleSelectComponent();
this.onContainerChange.cancel?.(); (this.onContainerChange as any).cancel?.();
this.onSelect.cancel?.(); (this.onSelect as any).cancel?.();
this.updateAttached.cancel?.(); (this.updateAttached as any).cancel?.();
this._upToolbar.cancel?.(); (this._upToolbar as any).cancel?.();
}, }
/** /**
* Toggle select component event * Toggle select component event
* @private * @private
* */ * */
toggleSelectComponent(enable: boolean) { toggleSelectComponent(enable?: boolean) {
const { em, canvas } = this; const { em, canvas } = this;
const canvasEl = canvas.getCanvasView().el; const canvasEl = canvas.getCanvasView().el;
const listenToEl = em.getConfig().listenToEl!; const listenToEl = em.getConfig().listenToEl!;
@ -88,8 +109,8 @@ export default {
const methods = { on, off }; const methods = { on, off };
const eventCmpUpdate = ComponentsEvents.update; const eventCmpUpdate = ComponentsEvents.update;
!listenToEl.length && parentNode && listenToEl.push(parentNode as HTMLElement); !listenToEl.length && parentNode && listenToEl.push(parentNode as HTMLElement);
const trigger = (win: Window, body: HTMLBodyElement, canvasEl: HTMLElement) => { const trigger = (win: Window, body: HTMLBodyElement, currentCanvasEl: HTMLElement) => {
methods[method](canvasEl, 'scroll', this.onCanvasScroll, true); methods[method](currentCanvasEl, 'scroll', this.onCanvasScroll, true);
methods[method](body, 'mouseover', this.onHover); methods[method](body, 'mouseover', this.onHover);
methods[method](body, 'mouseleave', this.onOut); methods[method](body, 'mouseleave', this.onOut);
methods[method](body, 'click', this.onClick); methods[method](body, 'click', this.onClick);
@ -105,12 +126,12 @@ export default {
em[method]('frame:updated', this.onFrameUpdated, this); em[method]('frame:updated', this.onFrameUpdated, this);
em[method](CanvasEvents.updateTools, this.onFrameUpdated, this); em[method](CanvasEvents.updateTools, this.onFrameUpdated, this);
em[method](em.Canvas.events.refresh, this.updateAttached, this); em[method](em.Canvas.events.refresh, this.updateAttached, this);
em.Canvas.getFrames().forEach((frame) => { em.Canvas.getFrames().forEach((frame: any) => {
const { view } = frame; const { view } = frame;
const win = view?.getWindow(); const win = view?.getWindow();
win && trigger(win, view?.getBody()!, canvasEl); win && trigger(win, view?.getBody()!, canvasEl);
}); });
}, }
/** /**
* Hover command * Hover command
@ -125,7 +146,6 @@ export default {
const frameView = view?.frameView; const frameView = view?.frameView;
let model = view?.model; let model = view?.model;
// Get first valid model
if (!model) { if (!model) {
let parentEl = el.parentNode; let parentEl = el.parentNode;
while (!model && parentEl && !isDoc(parentEl)) { while (!model && parentEl && !isDoc(parentEl)) {
@ -137,14 +157,14 @@ export default {
this.currentDoc = el.ownerDocument; this.currentDoc = el.ownerDocument;
em.setHovered(model, { useValid: true }); em.setHovered(model, { useValid: true });
frameView && em.setCurrentFrame(frameView); frameView && em.setCurrentFrame(frameView);
}, }
onFrameUpdated() { onFrameUpdated() {
this.updateLocalPos(); this.updateLocalPos();
this.updateGlobalPos(); this.updateGlobalPos();
}, }
onHovered(em: any, component: Component) { onHovered(em?: any, component?: Component) {
let result = {}; let result = {};
if (component) { if (component) {
@ -163,18 +183,16 @@ export default {
this.currentDoc = null; this.currentDoc = null;
this.elHovered = 0; this.elHovered = 0;
this.updateToolsLocal(); this.updateToolsLocal();
this.canvas.getFrames().forEach((frame) => { this.canvas.getFrames().forEach((frame: any) => {
const { view } = frame; const { view } = frame;
const el = view && view.getToolsEl(); const el = view && view.getToolsEl();
el && this.toggleToolsEl(0, 0, { el }); el && this.toggleToolsEl(false, 0, { el });
}); });
} }
}, }
/** /**
* Say what to do after the component was selected * Say what to do after the component was selected
* @param {Object} e
* @param {Object} el
* @private * @private
* */ * */
onSelect() { onSelect() {
@ -182,7 +200,7 @@ export default {
const component = em.getSelected(); const component = em.getSelected();
const currentFrame = em.getCurrentFrame(); const currentFrame = em.getCurrentFrame();
const view = component && component.getView(currentFrame?.model); const view = component && component.getView(currentFrame?.model);
let el = view?.el; const el = view?.el;
let result = {}; let result = {};
if (el && isVisible(el)) { if (el && isVisible(el)) {
@ -192,48 +210,42 @@ export default {
this.elSelected = result; this.elSelected = result;
this.updateToolsGlobal(); this.updateToolsGlobal();
// This will hide some elements from the select component
this.updateLocalPos(result); this.updateLocalPos(result);
this.initResize(component); this.initResize(component);
}, }
updateGlobalPos() { updateGlobalPos() {
const sel = this.getElSelected(); const sel = this.getElSelected();
if (!sel.el) return; if (!sel.el) return;
sel.pos = this.getElementPos(sel.el); sel.pos = this.getElementPos(sel.el);
this.updateToolsGlobal(); this.updateToolsGlobal();
}, }
updateLocalPos(data: any) { updateLocalPos(data?: any) {
const sel = this.getElHovered(); const sel = this.getElHovered();
if (!sel.el) return; if (!sel.el) return;
sel.pos = this.getElementPos(sel.el); sel.pos = this.getElementPos(sel.el);
this.updateToolsLocal(data); this.updateToolsLocal(data);
}, }
getElHovered() { getElHovered() {
return this.elHovered || {}; return this.elHovered || {};
}, }
getElSelected() { getElSelected() {
return this.elSelected || {}; return this.elSelected || {};
}, }
onOut() { onOut() {
this.em.setHovered(); this.em.setHovered();
}, }
toggleToolsEl(on: boolean, view: any, opts: any = {}) { toggleToolsEl(on?: boolean, view?: any, opts: any = {}) {
const el = opts.el || this.canvas.getToolsEl(view); const el = opts.el || this.canvas.getToolsEl(view);
el && (el.style.display = on ? '' : 'none'); el && (el.style.display = on ? '' : 'none');
return el || {}; return el || {};
}, }
/**
* Show element offset viewer
* @param {HTMLElement} el
* @param {Object} pos
*/
showElementOffset(el: HTMLElement, pos: any, opts: any = {}) { showElementOffset(el: HTMLElement, pos: any, opts: any = {}) {
if (!showOffsets) return; if (!showOffsets) return;
this.editor.runCommand('show-offset', { this.editor.runCommand('show-offset', {
@ -244,53 +256,30 @@ export default {
top: 0, top: 0,
left: 0, left: 0,
}); });
}, }
/**
* Hide element offset viewer
* @param {HTMLElement} el
* @param {Object} pos
*/
hideElementOffset(view: any) { hideElementOffset(view: any) {
this.editor.stopCommand('show-offset', { this.editor.stopCommand('show-offset', {
view, view,
}); });
}, }
/**
* Show fixed element offset viewer
* @param {HTMLElement} el
* @param {Object} pos
*/
showFixedElementOffset(el: HTMLElement, pos: any) { showFixedElementOffset(el: HTMLElement, pos: any) {
this.editor.runCommand('show-offset', { this.editor.runCommand('show-offset', {
el, el,
elPos: pos, elPos: pos,
state: 'Fixed', state: 'Fixed',
}); });
}, }
/**
* Hide fixed element offset viewer
* @param {HTMLElement} el
* @param {Object} pos
*/
hideFixedElementOffset() { hideFixedElementOffset() {
if (this.editor) this.editor.stopCommand('show-offset', { state: 'Fixed' }); if (this.editor) this.editor.stopCommand('show-offset', { state: 'Fixed' });
}, }
/**
* Hide Highlighter element
*/
hideHighlighter(view: any) { hideHighlighter(view: any) {
this.canvas.getHighlighter(view).style.opacity = 0; this.canvas.getHighlighter(view).style.opacity = 0;
}, }
/**
* On element click
* @param {Event} e
* @private
*/
onClick(ev: Event) { onClick(ev: Event) {
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
@ -313,38 +302,22 @@ export default {
if (cmp) { if (cmp) {
if ( if (
em.isEditing() && em.isEditing() &&
// Avoid selection of inner text components during editing ((!cmp.get('textable') && cmp.isChildOf('text')) || em.getEditing() !== cmp)
((!cmp.get('textable') && cmp.isChildOf('text')) ||
// Prevents selecting another component if the pointer was pressed and
// dragged outside of the editing component
em.getEditing() !== cmp)
) { ) {
return; return;
} }
this.select(cmp, ev); this.select(cmp, ev as MouseEvent);
} }
}, }
/**
* Select component
* @param {Component} model
* @param {Event} event
*/
select(model: Component, event: MouseEvent) { select(model: Component, event: MouseEvent) {
if (!model) return; if (!model) return;
const { em } = this; const { em } = this;
em.setSelected(model, { event, useValid: true }); em.setSelected(model, { event, useValid: true });
// Ensure we're passing the proper selected component #6096
this.initResize(em.getSelected()); this.initResize(em.getSelected());
}, }
/**
* Update badge for the component
* @param {Object} Component
* @param {Object} pos Position object
* @private
* */
updateBadge(el: HTMLElement, pos: any, opts: any = {}) { updateBadge(el: HTMLElement, pos: any, opts: any = {}) {
const { canvas } = this; const { canvas } = this;
const model = getComponentModel(el); const model = getComponentModel(el);
@ -374,29 +347,18 @@ export default {
pos: pos, pos: pos,
}); });
const top = targetToElem.top; //opts.topOff - badgeH < 0 ? -opts.topOff : posTop; const top = targetToElem.top;
const left = opts.leftOff < 0 ? -opts.leftOff : 0; const left = opts.leftOff < 0 ? -opts.leftOff : 0;
bStyle.top = top + un; bStyle.top = top + un;
bStyle.left = left + un; bStyle.left = left + un;
}, }
/**
* Update highlighter element
* @param {HTMLElement} el
* @param {Object} pos Position object
* @private
*/
showHighlighter(view: any) { showHighlighter(view: any) {
this.canvas.getHighlighter(view).style.opacity = ''; this.canvas.getHighlighter(view).style.opacity = '';
}, }
/** initResize(elem: any) {
* Init resizer on the element if possible
* @param {HTMLElement|Component} elem
* @private
*/
initResize(elem: HTMLElement) {
const { em, canvas } = this; const { em, canvas } = this;
const editor = em.Editor; const editor = em.Editor;
const component = !isElement(elem) && isTaggableNode(elem) ? elem : em.getSelected(); const component = !isElement(elem) && isTaggableNode(elem) ? elem : em.getSelected();
@ -440,13 +402,9 @@ export default {
editor.stopCommand('resize'); editor.stopCommand('resize');
this.resizer = null; this.resizer = null;
} }
}, }
/** updateToolbar(mod: any) {
* Update toolbar if the component has one
* @param {Object} mod
*/
updateToolbar(mod: Component) {
const { canvas } = this; const { canvas } = this;
const { em } = this.config; const { em } = this.config;
const model = mod === em ? em.getSelected() : mod; const model = mod === em ? em.getSelected() : mod;
@ -461,8 +419,7 @@ export default {
if (!this.toolbar) { if (!this.toolbar) {
toolbarEl.innerHTML = ''; toolbarEl.innerHTML = '';
this.toolbar = new Toolbar(toolbar); this.toolbar = new Toolbar(toolbar);
// @ts-ignore const toolbarView = new ToolbarView({ collection: this.toolbar, em } as any);
const toolbarView = new ToolbarView({ collection: this.toolbar, em });
toolbarEl.appendChild(toolbarView.render().el); toolbarEl.appendChild(toolbarView.render().el);
} }
@ -472,75 +429,48 @@ export default {
} else { } else {
toolbarStyle.display = 'none'; toolbarStyle.display = 'none';
} }
}, }
/**
* Update toolbar positions
* @param {HTMLElement} el
* @param {Object} pos
*/
updateToolbarPos(pos: any) { updateToolbarPos(pos: any) {
const unit = 'px'; const unit = 'px';
const { style } = this.canvas.getToolbarEl()!; const { style } = this.canvas.getToolbarEl()!;
style.top = `${pos.top}${unit}`; style.top = `${pos.top}${unit}`;
style.left = `${pos.left}${unit}`; style.left = `${pos.left}${unit}`;
style.opacity = ''; style.opacity = '';
}, }
/**
* Return canvas dimensions and positions
* @return {Object}
*/
getCanvasPosition() { getCanvasPosition() {
return this.canvas.getCanvasView().getPosition(); return this.canvas.getCanvasView().getPosition();
}, }
/**
* Returns badge element
* @return {HTMLElement}
* @private
*/
getBadge(opts: any = {}) { getBadge(opts: any = {}) {
return this.canvas.getBadgeEl(opts.view); return this.canvas.getBadgeEl(opts.view);
}, }
/**
* On canvas scroll callback
* @private
*/
onCanvasScroll(e: any) { onCanvasScroll(e: any) {
this.onFrameScroll(e); this.onFrameScroll(e);
this.onContainerChange(); this.onContainerChange();
}, }
/** onFrameScroll(_e?: any) {
* On frame scroll callback
* @private
*/
onFrameScroll() {
this.updateTools(); this.updateTools();
this.canvas.refreshSpots(); this.canvas.refreshSpots();
}, }
onFrameResize() { onFrameResize() {
this.canvas.refresh({ all: true }); this.canvas.refresh({ all: true });
}, }
updateTools() { updateTools() {
this.updateLocalPos(); this.updateLocalPos();
this.updateGlobalPos(); this.updateGlobalPos();
}, }
isCompSelected(comp: Component) { isCompSelected(comp: Component) {
return comp && comp.get('status') === 'selected'; return comp && comp.get('status') === 'selected';
}, }
/** updateToolsLocal(data?: any) {
* Update tools visible on hover
* @param {HTMLElement} el
* @param {Object} pos
*/
updateToolsLocal(data: any) {
const config = this.em.getConfig(); const config = this.em.getConfig();
const { el, pos, view, component } = data || this.getElHovered(); const { el, pos, view, component } = data || this.getElHovered();
@ -566,7 +496,7 @@ export default {
} }
const unit = 'px'; const unit = 'px';
const toolsEl = this.toggleToolsEl(1, view); const toolsEl = this.toggleToolsEl(true, view);
const { style } = toolsEl; const { style } = toolsEl;
const frameOff = this.canvas.canvasRectOffset(el, pos); const frameOff = this.canvas.canvasRectOffset(el, pos);
const topOff = frameOff.top; const topOff = frameOff.top;
@ -593,25 +523,22 @@ export default {
width: pos.width, width: pos.width,
height: pos.height, height: pos.height,
}); });
}, }
_upToolbar: debounce(function () { _upToolbar() {}
// @ts-ignore
this.updateToolsGlobal({ force: 1 });
}, 0),
_trgToolUp(type: string, opts = {}) { _trgToolUp(type: string, opts = {}) {
this.em.trigger(CanvasEvents.toolsUpdate, { this.em.trigger(CanvasEvents.toolsUpdate, {
type, type,
...opts, ...opts,
}); });
}, }
updateToolsGlobal(opts: any = {}) { updateToolsGlobal(opts: any = {}) {
const { el, pos, component } = this.getElSelected(); const { el, pos, component } = this.getElSelected();
if (!el) { if (!el) {
this.toggleToolsEl(); // Hides toolbar this.toggleToolsEl();
this.lastSelected = 0; this.lastSelected = 0;
return; return;
} }
@ -625,7 +552,7 @@ export default {
} }
const unit = 'px'; const unit = 'px';
const toolsEl = this.toggleToolsEl(1); const toolsEl = this.toggleToolsEl(true);
const { style } = toolsEl; const { style } = toolsEl;
const targetToElem = canvas.getTargetToElementFixed(el, canvas.getToolbarEl()!, { pos }); const targetToElem = canvas.getTargetToElementFixed(el, canvas.getToolbarEl()!, { pos });
const topOff = targetToElem.canvasOffsetTop; const topOff = targetToElem.canvasOffsetTop;
@ -644,74 +571,45 @@ export default {
width: pos.width, width: pos.width,
height: pos.height, height: pos.height,
}); });
}, }
/** updateAttached() {}
* Update attached elements, eg. component toolbar
*/
updateAttached: debounce(function () {
// @ts-ignore
this.updateGlobalPos();
}, 0),
onContainerChange: debounce(function () { onContainerChange() {}
// @ts-ignore
this.em.refreshCanvas();
}, 150),
/**
* Returns element's data info
* @param {HTMLElement} el
* @return {Object}
* @private
*/
getElementPos(el: HTMLElement) { getElementPos(el: HTMLElement) {
return this.canvas.getCanvasView().getElementPos(el, { noScroll: true }); return this.canvas.getCanvasView().getElementPos(el, { noScroll: true });
}, }
/**
* Hide badge
* @private
* */
hideBadge() { hideBadge() {
this.getBadge().style.display = 'none'; this.getBadge().style.display = 'none';
}, }
/**
* Clean previous model from different states
* @param {Component} model
* @private
*/
cleanPrevious(model: Component) { cleanPrevious(model: Component) {
model && model &&
model.set({ model.set({
status: '', status: '',
state: '', state: '',
}); });
}, }
/**
* Returns content window
* @private
*/
getContentWindow() { getContentWindow() {
return this.canvas.getWindow(); return this.canvas.getWindow();
}, }
run(editor) { run(editor: any) {
if (!hasWin()) return; if (!hasWin()) return;
// @ts-ignore
this.editor = editor && editor.get('Editor'); this.editor = editor && editor.get('Editor');
this.enable(); this.enable();
}, }
stop(ed, sender, opts = {}) { stop(ed?: any, sender?: any, opts: any = {}) {
if (!hasWin()) return; if (!hasWin()) return;
const { em, editor } = this; const { em, editor } = this;
this.onHovered(); // force to hide toolbar this.onHovered();
this.stopSelectComponent(); this.stopSelectComponent();
!opts.preserveSelected && em.setSelected(); !opts.preserveSelected && em.setSelected();
this.toggleToolsEl(); this.toggleToolsEl();
editor?.stopCommand('resize'); editor?.stopCommand('resize');
}, }
} as CommandObject<any, { [k: string]: any }>; }

30
packages/core/test/specs/commands/view/SelectComponent.ts

@ -0,0 +1,30 @@
import SelectComponent from '../../../../src/commands/view/SelectComponent';
describe('SelectComponent command', () => {
test('select should update editor selection and initialize resize', () => {
const command = new SelectComponent({});
const selected = { id: 'cmp-selected' };
const setSelected = jest.fn();
const getSelected = jest.fn(() => selected);
command.em = { setSelected, getSelected } as any;
command.initResize = jest.fn();
const model = { id: 'cmp-1' } as any;
const event = {} as MouseEvent;
command.select(model, event);
expect(setSelected).toHaveBeenCalledWith(model, { event, useValid: true });
expect(command.initResize).toHaveBeenCalledWith(selected);
});
test('hideBadge should hide the badge element', () => {
const command = new SelectComponent({});
const badge = document.createElement('div');
badge.style.display = 'block';
command.getBadge = jest.fn(() => badge);
command.hideBadge();
expect(badge.style.display).toBe('none');
});
});
Loading…
Cancel
Save