@eclipse-glsp/client 0.10.0-next.e5fcffe.169 → 1.1.0-next.fe0b297.182

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/css/decoration.css +5 -1
  2. package/css/glsp-sprotty.css +39 -0
  3. package/css/tool-palette.css +2 -2
  4. package/lib/base/container-modules.d.ts.map +1 -1
  5. package/lib/base/container-modules.js +10 -9
  6. package/lib/base/container-modules.js.map +1 -1
  7. package/lib/base/editor-context-service.d.ts +2 -3
  8. package/lib/base/editor-context-service.d.ts.map +1 -1
  9. package/lib/base/editor-context-service.js +11 -12
  10. package/lib/base/editor-context-service.js.map +1 -1
  11. package/lib/base/model/update-model-command.d.ts +14 -7
  12. package/lib/base/model/update-model-command.d.ts.map +1 -1
  13. package/lib/base/model/update-model-command.js +31 -41
  14. package/lib/base/model/update-model-command.js.map +1 -1
  15. package/lib/base/source-uri-aware.d.ts +2 -17
  16. package/lib/base/source-uri-aware.d.ts.map +1 -1
  17. package/lib/base/source-uri-aware.js +4 -6
  18. package/lib/base/source-uri-aware.js.map +1 -1
  19. package/lib/features/change-bounds/movement-restrictor.d.ts +36 -6
  20. package/lib/features/change-bounds/movement-restrictor.d.ts.map +1 -1
  21. package/lib/features/change-bounds/movement-restrictor.js +54 -39
  22. package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
  23. package/lib/features/change-bounds/snap.d.ts +20 -5
  24. package/lib/features/change-bounds/snap.d.ts.map +1 -1
  25. package/lib/features/change-bounds/snap.js +19 -8
  26. package/lib/features/change-bounds/snap.js.map +1 -1
  27. package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts +5 -7
  28. package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts.map +1 -1
  29. package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js +7 -14
  30. package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js.map +1 -1
  31. package/lib/features/hover/hover.d.ts +1 -2
  32. package/lib/features/hover/hover.d.ts.map +1 -1
  33. package/lib/features/hover/hover.js +2 -15
  34. package/lib/features/hover/hover.js.map +1 -1
  35. package/lib/features/layout/di.config.d.ts +2 -2
  36. package/lib/features/layout/di.config.d.ts.map +1 -1
  37. package/lib/features/layout/di.config.js +6 -5
  38. package/lib/features/layout/di.config.js.map +1 -1
  39. package/lib/features/layout/{layout-commands.d.ts → layout-elements-action.d.ts} +75 -57
  40. package/lib/features/layout/layout-elements-action.d.ts.map +1 -0
  41. package/lib/features/layout/{layout-commands.js → layout-elements-action.js} +153 -197
  42. package/lib/features/layout/layout-elements-action.js.map +1 -0
  43. package/lib/features/layout/layout-elements-action.spec.d.ts +3 -0
  44. package/lib/features/layout/layout-elements-action.spec.d.ts.map +1 -0
  45. package/lib/features/layout/{layout-commands.spec.js → layout-elements-action.spec.js} +63 -56
  46. package/lib/features/layout/layout-elements-action.spec.js.map +1 -0
  47. package/lib/features/mouse-tool/mouse-tool.d.ts +0 -1
  48. package/lib/features/mouse-tool/mouse-tool.d.ts.map +1 -1
  49. package/lib/features/mouse-tool/mouse-tool.js +9 -5
  50. package/lib/features/mouse-tool/mouse-tool.js.map +1 -1
  51. package/lib/features/select/select-mouse-listener.d.ts +3 -1
  52. package/lib/features/select/select-mouse-listener.d.ts.map +1 -1
  53. package/lib/features/select/select-mouse-listener.js +62 -0
  54. package/lib/features/select/select-mouse-listener.js.map +1 -1
  55. package/lib/features/select/selection-service.d.ts +12 -3
  56. package/lib/features/select/selection-service.d.ts.map +1 -1
  57. package/lib/features/select/selection-service.js +31 -45
  58. package/lib/features/select/selection-service.js.map +1 -1
  59. package/lib/features/select/selection-service.spec.js +1 -1
  60. package/lib/features/select/selection-service.spec.js.map +1 -1
  61. package/lib/features/source-model-watcher/di.config.d.ts +4 -0
  62. package/lib/features/{model-source-watcher → source-model-watcher}/di.config.d.ts.map +1 -1
  63. package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js +4 -4
  64. package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js.map +1 -1
  65. package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts → source-model-watcher/source-model-changed-action-handler.d.ts} +9 -9
  66. package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts.map → source-model-watcher/source-model-changed-action-handler.d.ts.map} +1 -1
  67. package/lib/features/{model-source-watcher/model-source-changed-action-handler.js → source-model-watcher/source-model-changed-action-handler.js} +19 -19
  68. package/lib/features/{model-source-watcher/model-source-changed-action-handler.js.map → source-model-watcher/source-model-changed-action-handler.js.map} +1 -1
  69. package/lib/features/tool-feedback/change-bounds-tool-feedback.js +1 -1
  70. package/lib/features/tool-feedback/change-bounds-tool-feedback.js.map +1 -1
  71. package/lib/features/tool-feedback/edge-edit-tool-feedback.d.ts +3 -2
  72. package/lib/features/tool-feedback/edge-edit-tool-feedback.d.ts.map +1 -1
  73. package/lib/features/tool-feedback/edge-edit-tool-feedback.js +13 -6
  74. package/lib/features/tool-feedback/edge-edit-tool-feedback.js.map +1 -1
  75. package/lib/features/tools/di.config.d.ts +9 -2
  76. package/lib/features/tools/di.config.d.ts.map +1 -1
  77. package/lib/features/tools/di.config.js +14 -3
  78. package/lib/features/tools/di.config.js.map +1 -1
  79. package/lib/features/tools/enable-default-tools-on-focus-loss.d.ts +26 -0
  80. package/lib/features/tools/enable-default-tools-on-focus-loss.d.ts.map +1 -0
  81. package/lib/features/tools/enable-default-tools-on-focus-loss.js +29 -0
  82. package/lib/features/tools/enable-default-tools-on-focus-loss.js.map +1 -0
  83. package/lib/features/validation/di.config.d.ts +0 -15
  84. package/lib/features/validation/di.config.d.ts.map +1 -1
  85. package/lib/features/validation/di.config.js +6 -4
  86. package/lib/features/validation/di.config.js.map +1 -1
  87. package/lib/features/validation/issue-marker.d.ts +11 -5
  88. package/lib/features/validation/issue-marker.d.ts.map +1 -1
  89. package/lib/features/validation/issue-marker.js +25 -5
  90. package/lib/features/validation/issue-marker.js.map +1 -1
  91. package/lib/features/validation/marker-navigator.d.ts +11 -17
  92. package/lib/features/validation/marker-navigator.d.ts.map +1 -1
  93. package/lib/features/validation/marker-navigator.js +32 -61
  94. package/lib/features/validation/marker-navigator.js.map +1 -1
  95. package/lib/features/validation/validate.d.ts +8 -19
  96. package/lib/features/validation/validate.d.ts.map +1 -1
  97. package/lib/features/validation/validate.js +29 -55
  98. package/lib/features/validation/validate.js.map +1 -1
  99. package/lib/index.d.ts +6 -6
  100. package/lib/index.d.ts.map +1 -1
  101. package/lib/index.js +16 -15
  102. package/lib/index.js.map +1 -1
  103. package/lib/lib/model.d.ts +1 -1
  104. package/lib/lib/model.d.ts.map +1 -1
  105. package/lib/lib/model.js +3 -3
  106. package/lib/lib/model.js.map +1 -1
  107. package/lib/model-source/glsp-diagram-server.d.ts +1 -1
  108. package/lib/model-source/glsp-diagram-server.d.ts.map +1 -1
  109. package/lib/model-source/glsp-diagram-server.js +1 -1
  110. package/lib/model-source/glsp-diagram-server.js.map +1 -1
  111. package/lib/utils/layout-utils.d.ts +4 -20
  112. package/lib/utils/layout-utils.d.ts.map +1 -1
  113. package/lib/utils/layout-utils.js +1 -1
  114. package/lib/utils/layout-utils.js.map +1 -1
  115. package/lib/views/base-view-module.d.ts.map +1 -1
  116. package/lib/views/base-view-module.js +3 -1
  117. package/lib/views/base-view-module.js.map +1 -1
  118. package/lib/views/glsp-projection-view.d.ts +30 -0
  119. package/lib/views/glsp-projection-view.d.ts.map +1 -0
  120. package/lib/views/glsp-projection-view.js +142 -0
  121. package/lib/views/glsp-projection-view.js.map +1 -0
  122. package/lib/views/index.d.ts +1 -0
  123. package/lib/views/index.d.ts.map +1 -1
  124. package/lib/views/index.js +1 -0
  125. package/lib/views/index.js.map +1 -1
  126. package/package.json +4 -4
  127. package/src/base/container-modules.ts +6 -5
  128. package/src/base/editor-context-service.ts +15 -7
  129. package/src/base/model/update-model-command.ts +48 -34
  130. package/src/base/source-uri-aware.ts +5 -4
  131. package/src/features/change-bounds/movement-restrictor.ts +73 -43
  132. package/src/features/change-bounds/snap.ts +15 -12
  133. package/src/features/context-menu/selection-service-aware-context-menu-mouse-listener.ts +19 -25
  134. package/src/features/hover/hover.ts +2 -24
  135. package/src/features/layout/di.config.ts +12 -6
  136. package/src/features/layout/{layout-commands.spec.ts → layout-elements-action.spec.ts} +56 -48
  137. package/src/features/layout/{layout-commands.ts → layout-elements-action.ts} +195 -207
  138. package/src/features/mouse-tool/mouse-tool.ts +8 -6
  139. package/src/features/select/select-mouse-listener.ts +81 -1
  140. package/src/features/select/selection-service.spec.ts +1 -1
  141. package/src/features/select/selection-service.ts +37 -50
  142. package/src/features/{model-source-watcher → source-model-watcher}/di.config.ts +5 -5
  143. package/src/features/{model-source-watcher/model-source-changed-action-handler.ts → source-model-watcher/source-model-changed-action-handler.ts} +12 -12
  144. package/src/features/tool-feedback/change-bounds-tool-feedback.ts +1 -1
  145. package/src/features/tool-feedback/edge-edit-tool-feedback.ts +14 -6
  146. package/src/features/tools/di.config.ts +13 -2
  147. package/src/features/tools/enable-default-tools-on-focus-loss.ts +33 -0
  148. package/src/features/validation/di.config.ts +10 -7
  149. package/src/features/validation/issue-marker.ts +34 -12
  150. package/src/features/validation/marker-navigator.ts +29 -66
  151. package/src/features/validation/validate.ts +36 -71
  152. package/src/index.ts +8 -7
  153. package/src/lib/model.ts +1 -1
  154. package/src/model-source/glsp-diagram-server.ts +1 -1
  155. package/src/utils/layout-utils.ts +7 -27
  156. package/src/views/base-view-module.ts +5 -1
  157. package/src/views/glsp-projection-view.tsx +166 -0
  158. package/src/views/index.ts +2 -0
  159. package/lib/features/layout/layout-commands.d.ts.map +0 -1
  160. package/lib/features/layout/layout-commands.js.map +0 -1
  161. package/lib/features/layout/layout-commands.spec.d.ts +0 -3
  162. package/lib/features/layout/layout-commands.spec.d.ts.map +0 -1
  163. package/lib/features/layout/layout-commands.spec.js.map +0 -1
  164. package/lib/features/model-source-watcher/di.config.d.ts +0 -4
@@ -13,25 +13,28 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Point } from '@eclipse-glsp/protocol';
16
+ import { Point, Writable } from '@eclipse-glsp/protocol';
17
17
  import { injectable } from 'inversify';
18
18
  import { findParentByFeature, ISnapper, isViewport, SModelElement } from 'sprotty';
19
- import { WriteablePoint } from '../../utils/layout-utils';
20
19
 
20
+ /**
21
+ * A {@link ISnapper} implementation that snaps all elements onto a fixed gride size.
22
+ * The default grid size is 10x10 pixel.
23
+ * To configure a custom grid size bind the `TYPES.ISnapper` service identifier
24
+ * to constant value, e.g:
25
+ *
26
+ * ```ts
27
+ * bind(TYPES.ISnapper).toConstantValue(new GridSnapper({x:25 ,y:25 }));
28
+ * ```
29
+ */
21
30
  @injectable()
22
31
  export class GridSnapper implements ISnapper {
23
- get gridX(): number {
24
- return 10;
25
- }
26
-
27
- get gridY(): number {
28
- return 10;
29
- }
32
+ constructor(public grid: { x: number; y: number } = { x: 10, y: 10 }) {}
30
33
 
31
34
  snap(position: Point, element: SModelElement): Point {
32
35
  return {
33
- x: Math.round(position.x / this.gridX) * this.gridX,
34
- y: Math.round(position.y / this.gridY) * this.gridY
36
+ x: Math.round(position.x / this.grid.x) * this.grid.x,
37
+ y: Math.round(position.y / this.grid.y) * this.grid.y
35
38
  };
36
39
  }
37
40
  }
@@ -46,7 +49,7 @@ export class GridSnapper implements ISnapper {
46
49
  */
47
50
  export class PointPositionUpdater {
48
51
  protected lastDragPosition?: Point;
49
- protected positionDelta: WriteablePoint = { x: 0, y: 0 };
52
+ protected positionDelta: Writable<Point> = { x: 0, y: 0 };
50
53
 
51
54
  constructor(protected snapper?: ISnapper) {}
52
55
 
@@ -15,53 +15,47 @@
15
15
  ********************************************************************************/
16
16
  import { Action } from '@eclipse-glsp/protocol';
17
17
  import { inject, injectable, optional } from 'inversify';
18
- import {
19
- ContextMenuProviderRegistry,
20
- findParentByFeature,
21
- IContextMenuServiceProvider,
22
- isSelectable,
23
- MouseListener,
24
- SModelElement
25
- } from 'sprotty';
18
+ import { ContextMenuProviderRegistry, IContextMenuServiceProvider, MouseListener, SModelElement } from 'sprotty';
26
19
  import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
27
20
  import { TYPES } from '../../base/types';
28
21
  import { SelectionService } from '../select/selection-service';
29
22
 
30
23
  @injectable()
31
24
  export class SelectionServiceAwareContextMenuMouseListener extends MouseListener {
32
- @inject(TYPES.IContextMenuServiceProvider) @optional() protected readonly contextMenuService: IContextMenuServiceProvider;
33
- @inject(TYPES.IContextMenuProviderRegistry) @optional() protected readonly menuProvider: ContextMenuProviderRegistry;
34
- @inject(TYPES.SelectionService) protected selectionService: SelectionService;
25
+ @inject(TYPES.IContextMenuServiceProvider)
26
+ @optional()
27
+ protected readonly contextMenuService?: IContextMenuServiceProvider;
28
+
29
+ @inject(TYPES.IContextMenuProviderRegistry)
30
+ @optional()
31
+ protected readonly menuProvider?: ContextMenuProviderRegistry;
32
+
33
+ @inject(TYPES.SelectionService)
34
+ protected selectionService: SelectionService;
35
35
 
36
36
  /**
37
- * Opens the context menu on right-click.
37
+ * Opens the context menu.
38
38
  */
39
- override mouseDown(target: SModelElement, event: MouseEvent): (Action | Promise<Action>)[] {
40
- if (event.button === 2 && this.contextMenuService && this.menuProvider) {
41
- return this.openContextMenu(event, target);
42
- }
43
- return [];
39
+ override contextMenu(target: SModelElement, event: MouseEvent): (Action | Promise<Action>)[] {
40
+ return this.openContextMenu(target, event);
44
41
  }
45
42
 
46
43
  /**
47
44
  * Opens the context menu.
48
45
  *
49
- * - query the element on the click-target
50
- * - select the element
51
46
  * - query the context menu service and the context menu elements
52
47
  * - show the context menu
53
48
  * - send a focus state change to indicate that the diagram becomes inactive, once the context menu is shown
54
49
  *
55
50
  * When the context menu is closed, we focus the diagram element again.
56
51
  */
57
- protected openContextMenu(event: MouseEvent, target: SModelElement): Promise<Action>[] {
58
- const mousePosition = { x: event.x, y: event.y };
59
- const selectableTarget = findParentByFeature(target, isSelectable);
60
- if (selectableTarget) {
61
- selectableTarget.selected = true;
62
- this.selectionService.updateSelection(target.root, [selectableTarget.id], []);
52
+ protected openContextMenu(target: SModelElement, event: MouseEvent): Promise<Action>[] {
53
+ if (!this.contextMenuService || !this.menuProvider) {
54
+ return [];
63
55
  }
64
56
 
57
+ const mousePosition = { x: event.x, y: event.y };
58
+
65
59
  const result = Promise.all([this.contextMenuService(), this.menuProvider.getItems(target.root, mousePosition)])
66
60
  .then(([menuService, menuItems]) => menuService.show(menuItems, mousePosition, () => this.focusEventTarget(event)))
67
61
  .then((): Action => FocusStateChangedAction.create(false));
@@ -23,20 +23,11 @@ import {
23
23
  SModelRootSchema
24
24
  } from '@eclipse-glsp/protocol';
25
25
  import { injectable } from 'inversify';
26
- import {
27
- EMPTY_ROOT,
28
- HoverFeedbackAction,
29
- HoverMouseListener,
30
- IActionHandler,
31
- ICommand,
32
- SIssueMarker,
33
- SIssueSeverity,
34
- SModelElement
35
- } from 'sprotty';
26
+ import { EMPTY_ROOT, HoverFeedbackAction, HoverMouseListener, IActionHandler, ICommand, SModelElement } from 'sprotty';
36
27
  import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
37
28
  import { EnableDefaultToolsAction, EnableToolsAction } from '../../base/tool-manager/tool-actions';
38
29
  import { EdgeCreationTool } from '../tools/edge-creation-tool';
39
- import { GIssueMarker } from '../validation/issue-marker';
30
+ import { getSeverity, GIssueMarker } from '../validation/issue-marker';
40
31
  @injectable()
41
32
  export class GlspHoverMouseListener extends HoverMouseListener implements IActionHandler {
42
33
  protected enableHover = true;
@@ -117,16 +108,3 @@ export class GlspHoverMouseListener extends HoverMouseListener implements IActio
117
108
  return bounds;
118
109
  }
119
110
  }
120
-
121
- export function getSeverity(marker: SIssueMarker): SIssueSeverity {
122
- let currentSeverity: SIssueSeverity = 'info';
123
- for (const severity of marker.issues.map(s => s.severity)) {
124
- if (severity === 'error') {
125
- return severity;
126
- }
127
- if (severity === 'warning' && currentSeverity === 'info') {
128
- currentSeverity = severity;
129
- }
130
- }
131
- return currentSeverity;
132
- }
@@ -14,19 +14,25 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
  import { ContainerModule } from 'inversify';
17
- import { configureCommand, configureLayout, HBoxLayouter, VBoxLayouter } from 'sprotty';
17
+ import { configureActionHandler, configureLayout, HBoxLayouter, VBoxLayouter } from 'sprotty';
18
18
  import { FreeFormLayouter } from './freeform-layout';
19
19
  import { HBoxLayouterExt } from './hbox-layout';
20
- import { AlignElementsCommand, ResizeElementsCommand } from './layout-commands';
20
+ import {
21
+ AlignElementsAction,
22
+ AlignElementsActionHandler,
23
+ ResizeElementsAction,
24
+ ResizeElementsActionHandler
25
+ } from './layout-elements-action';
21
26
  import { VBoxLayouterExt } from './vbox-layout';
22
27
 
23
- const layoutCommandsModule = new ContainerModule((bind, _unbind, isBound, rebind) => {
24
- configureCommand({ bind, isBound }, ResizeElementsCommand);
25
- configureCommand({ bind, isBound }, AlignElementsCommand);
28
+ const layoutModule = new ContainerModule((bind, _unbind, isBound, rebind) => {
29
+ const context = { bind, isBound };
30
+ configureActionHandler(context, ResizeElementsAction.KIND, ResizeElementsActionHandler);
31
+ configureActionHandler(context, AlignElementsAction.KIND, AlignElementsActionHandler);
26
32
 
27
33
  rebind(VBoxLayouter).to(VBoxLayouterExt);
28
34
  rebind(HBoxLayouter).to(HBoxLayouterExt);
29
35
  configureLayout({ bind, isBound }, FreeFormLayouter.KIND, FreeFormLayouter);
30
36
  });
31
37
 
32
- export default layoutCommandsModule;
38
+ export default layoutModule;
@@ -48,13 +48,12 @@ import { SelectionService } from '../select/selection-service';
48
48
  import { FeedbackActionDispatcher } from '../tool-feedback/feedback-action-dispatcher';
49
49
  import {
50
50
  AlignElementsAction,
51
- AlignElementsCommand,
51
+ AlignElementsActionHandler,
52
52
  Alignment,
53
- Reduce,
54
53
  ResizeDimension,
55
54
  ResizeElementsAction,
56
- ResizeElementsCommand
57
- } from './layout-commands';
55
+ ResizeElementsActionHandler
56
+ } from './layout-elements-action';
58
57
 
59
58
  class MockActionDispatcher implements IActionDispatcher {
60
59
  constructor(public dispatchedActions: Action[] = []) {}
@@ -71,14 +70,21 @@ class MockActionDispatcher implements IActionDispatcher {
71
70
  }
72
71
  }
73
72
 
73
+ class MockSelectionService extends SelectionService {
74
+ constructor(public modelRoot: SModelRoot) {
75
+ super();
76
+ }
77
+ override getModelRoot(): Readonly<SModelRoot> {
78
+ return this.modelRoot;
79
+ }
80
+ }
81
+
82
+ // Generic Test setup
74
83
  const container = new Container();
75
84
  container.load(defaultModule);
76
85
  container.bind(TYPES.IFeedbackActionDispatcher).to(FeedbackActionDispatcher).inSingletonScope();
77
- container.bind(SelectionService).toSelf().inSingletonScope();
78
- container.bind(TYPES.SelectionService).toService(SelectionService);
79
86
  container.rebind(TYPES.IModelFactory).to(SGraphFactory).inSingletonScope();
80
87
  const graphFactory = container.get<SGraphFactory>(TYPES.IModelFactory);
81
- const selectionService = container.get<SelectionService>(TYPES.SelectionService);
82
88
 
83
89
  const actionDispatcher = new MockActionDispatcher();
84
90
 
@@ -125,16 +131,26 @@ const context: CommandExecutionContext = {
125
131
  const defaultSize = { height: 10, width: 10 };
126
132
 
127
133
  describe('AlignElementsCommand', () => {
128
- it('should align all elements left', () => {
134
+ let handler: AlignElementsActionHandler;
135
+ const setModel = (newModel: SModelRoot): void => {
136
+ handler['selectionService'] = new MockSelectionService(newModel);
137
+ };
138
+
139
+ beforeEach(() => {
129
140
  actionDispatcher.dispatchedActions = [];
141
+
142
+ handler = new AlignElementsActionHandler();
143
+ handler['actionDispatcher'] = actionDispatcher;
144
+ });
145
+ it('should align all elements left', () => {
130
146
  const newModel = initModel([
131
147
  { elementId: 'node1', newPosition: { x: 111, y: 111 }, newSize: defaultSize },
132
148
  { elementId: 'node2', newPosition: { x: 222, y: 222 }, newSize: defaultSize },
133
149
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
134
150
  ]);
135
151
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Left });
136
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
137
- command.execute(newContext(newModel));
152
+ setModel(newModel);
153
+ handler.handle(action);
138
154
 
139
155
  assertAllBounds(
140
156
  new Map([
@@ -146,16 +162,14 @@ describe('AlignElementsCommand', () => {
146
162
  });
147
163
 
148
164
  it('should align all elements right', () => {
149
- actionDispatcher.dispatchedActions = [];
150
165
  const newModel = initModel([
151
166
  { elementId: 'node1', newPosition: { x: 111, y: 111 }, newSize: defaultSize },
152
167
  { elementId: 'node2', newPosition: { x: 222, y: 222 }, newSize: defaultSize },
153
168
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
154
169
  ]);
155
170
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Right });
156
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
157
- command.execute(newContext(newModel));
158
-
171
+ setModel(newModel);
172
+ handler.handle(action);
159
173
  assertAllBounds(
160
174
  new Map([
161
175
  ['node1', { x: 333, y: 111, width: defaultSize.width, height: defaultSize.height }],
@@ -173,8 +187,8 @@ describe('AlignElementsCommand', () => {
173
187
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
174
188
  ]);
175
189
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Center });
176
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
177
- command.execute(newContext(newModel));
190
+ setModel(newModel);
191
+ handler.handle(action);
178
192
 
179
193
  assertAllBounds(
180
194
  new Map([
@@ -186,15 +200,14 @@ describe('AlignElementsCommand', () => {
186
200
  });
187
201
 
188
202
  it('should align all elements top', () => {
189
- actionDispatcher.dispatchedActions = [];
190
203
  const newModel = initModel([
191
204
  { elementId: 'node1', newPosition: { x: 111, y: 111 }, newSize: defaultSize },
192
205
  { elementId: 'node2', newPosition: { x: 222, y: 222 }, newSize: defaultSize },
193
206
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
194
207
  ]);
195
208
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Top });
196
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
197
- command.execute(newContext(newModel));
209
+ setModel(newModel);
210
+ handler.handle(action);
198
211
 
199
212
  assertAllBounds(
200
213
  new Map([
@@ -206,15 +219,14 @@ describe('AlignElementsCommand', () => {
206
219
  });
207
220
 
208
221
  it('should align all elements bottom', () => {
209
- actionDispatcher.dispatchedActions = [];
210
222
  const newModel = initModel([
211
223
  { elementId: 'node1', newPosition: { x: 111, y: 111 }, newSize: defaultSize },
212
224
  { elementId: 'node2', newPosition: { x: 222, y: 222 }, newSize: defaultSize },
213
225
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
214
226
  ]);
215
227
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Bottom });
216
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
217
- command.execute(newContext(newModel));
228
+ setModel(newModel);
229
+ handler.handle(action);
218
230
 
219
231
  assertAllBounds(
220
232
  new Map([
@@ -226,15 +238,14 @@ describe('AlignElementsCommand', () => {
226
238
  });
227
239
 
228
240
  it('should align all elements middle', () => {
229
- actionDispatcher.dispatchedActions = [];
230
241
  const newModel = initModel([
231
242
  { elementId: 'node1', newPosition: { x: 111, y: 111 }, newSize: defaultSize },
232
243
  { elementId: 'node2', newPosition: { x: 222, y: 222 }, newSize: defaultSize },
233
244
  { elementId: 'node3', newPosition: { x: 333, y: 333 }, newSize: defaultSize }
234
245
  ]);
235
246
  const action = AlignElementsAction.create({ elementIds: ['node1', 'node2', 'node3'], alignment: Alignment.Middle });
236
- const command = new AlignElementsCommand(action, actionDispatcher, selectionService);
237
- command.execute(newContext(newModel));
247
+ setModel(newModel);
248
+ handler.handle(action);
238
249
 
239
250
  assertAllBounds(
240
251
  new Map([
@@ -247,8 +258,18 @@ describe('AlignElementsCommand', () => {
247
258
  });
248
259
 
249
260
  describe('ResizeElementsCommand', () => {
250
- it('should make same width as last', () => {
261
+ let handler: ResizeElementsActionHandler;
262
+ const setModel = (newModel: SModelRoot): void => {
263
+ handler['selectionService'] = new MockSelectionService(newModel);
264
+ };
265
+
266
+ beforeEach(() => {
251
267
  actionDispatcher.dispatchedActions = [];
268
+
269
+ handler = new ResizeElementsActionHandler();
270
+ handler['actionDispatcher'] = actionDispatcher;
271
+ });
272
+ it('should make same width as last', () => {
252
273
  const newModel = initModel([
253
274
  { elementId: 'node1', newPosition: { x: 100, y: 100 }, newSize: { height: 10, width: 10 } },
254
275
  { elementId: 'node2', newPosition: { x: 100, y: 200 }, newSize: { height: 20, width: 20 } },
@@ -257,10 +278,10 @@ describe('ResizeElementsCommand', () => {
257
278
  const action = ResizeElementsAction.create({
258
279
  elementIds: ['node1', 'node2', 'node3'],
259
280
  dimension: ResizeDimension.Width,
260
- reductionFunction: Reduce.last
281
+ reduceFunction: 'last'
261
282
  });
262
- const command = new ResizeElementsCommand(action, actionDispatcher, selectionService);
263
- command.execute(newContext(newModel));
283
+ setModel(newModel);
284
+ handler.handle(action);
264
285
 
265
286
  // resize is keeping the center, so the X moves by diff / 2
266
287
  assertAllBoundsInChangeBounds(
@@ -273,7 +294,6 @@ describe('ResizeElementsCommand', () => {
273
294
  });
274
295
 
275
296
  it('should make same height as last', () => {
276
- actionDispatcher.dispatchedActions = [];
277
297
  const newModel = initModel([
278
298
  { elementId: 'node1', newPosition: { x: 100, y: 100 }, newSize: { height: 10, width: 10 } },
279
299
  { elementId: 'node2', newPosition: { x: 100, y: 200 }, newSize: { height: 20, width: 20 } },
@@ -282,10 +302,10 @@ describe('ResizeElementsCommand', () => {
282
302
  const action = ResizeElementsAction.create({
283
303
  elementIds: ['node1', 'node2', 'node3'],
284
304
  dimension: ResizeDimension.Height,
285
- reductionFunction: Reduce.last
305
+ reduceFunction: 'last'
286
306
  });
287
- const command = new ResizeElementsCommand(action, actionDispatcher, selectionService);
288
- command.execute(newContext(newModel));
307
+ setModel(newModel);
308
+ handler.handle(action);
289
309
 
290
310
  // resize is keeping the center, so the Y moves by diff / 2
291
311
  assertAllBoundsInChangeBounds(
@@ -298,7 +318,6 @@ describe('ResizeElementsCommand', () => {
298
318
  });
299
319
 
300
320
  it('should make same width and height as last', () => {
301
- actionDispatcher.dispatchedActions = [];
302
321
  const newModel = initModel([
303
322
  { elementId: 'node1', newPosition: { x: 100, y: 100 }, newSize: { height: 10, width: 10 } },
304
323
  { elementId: 'node2', newPosition: { x: 100, y: 200 }, newSize: { height: 20, width: 20 } },
@@ -307,10 +326,10 @@ describe('ResizeElementsCommand', () => {
307
326
  const action = ResizeElementsAction.create({
308
327
  elementIds: ['node1', 'node2', 'node3'],
309
328
  dimension: ResizeDimension.Width_And_Height,
310
- reductionFunction: Reduce.last
329
+ reduceFunction: 'last'
311
330
  });
312
- const command = new ResizeElementsCommand(action, actionDispatcher, selectionService);
313
- command.execute(newContext(newModel));
331
+ setModel(newModel);
332
+ handler.handle(action);
314
333
 
315
334
  // resize is keeping the center, so the Y moves by diff / 2
316
335
  assertAllBoundsInChangeBounds(
@@ -329,17 +348,6 @@ function initModel(elementAndBounds: ElementAndBounds[]): SModelRoot {
329
348
  return setBoundsCommand.execute(context) as SModelRoot;
330
349
  }
331
350
 
332
- function newContext(root: SModelRoot): CommandExecutionContext {
333
- return {
334
- root: root,
335
- modelFactory: graphFactory,
336
- duration: 0,
337
- modelChanged: undefined!,
338
- logger: new ConsoleLogger(),
339
- syncer: new AnimationFrameSyncer()
340
- };
341
- }
342
-
343
351
  function assertAllBounds(allBounds: Map<string, Bounds>): void {
344
352
  allBounds.forEach((bounds, nodeId) => assertBounds(nodeId, bounds));
345
353
  }