@eclipse-glsp/client 2.1.1 → 2.2.0-next.325

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/ghost-element.css +3 -1
  2. package/css/glsp-sprotty.css +4 -5
  3. package/lib/base/action-dispatcher.d.ts +3 -2
  4. package/lib/base/action-dispatcher.d.ts.map +1 -1
  5. package/lib/base/action-dispatcher.js +17 -2
  6. package/lib/base/action-dispatcher.js.map +1 -1
  7. package/lib/base/action-dispatcher.spec.js +2 -2
  8. package/lib/base/action-dispatcher.spec.js.map +1 -1
  9. package/lib/base/action-handler-registry.d.ts +6 -2
  10. package/lib/base/action-handler-registry.d.ts.map +1 -1
  11. package/lib/base/action-handler-registry.js +31 -3
  12. package/lib/base/action-handler-registry.js.map +1 -1
  13. package/lib/base/command-stack.d.ts +8 -16
  14. package/lib/base/command-stack.d.ts.map +1 -1
  15. package/lib/base/command-stack.js +15 -14
  16. package/lib/base/command-stack.js.map +1 -1
  17. package/lib/base/default.module.d.ts +1 -1
  18. package/lib/base/default.module.d.ts.map +1 -1
  19. package/lib/base/default.module.js +16 -3
  20. package/lib/base/default.module.js.map +1 -1
  21. package/lib/base/editor-context-service.d.ts +44 -3
  22. package/lib/base/editor-context-service.d.ts.map +1 -1
  23. package/lib/base/editor-context-service.js +36 -13
  24. package/lib/base/editor-context-service.js.map +1 -1
  25. package/lib/base/feedback/feedback-action-dispatcher.d.ts +28 -1
  26. package/lib/base/feedback/feedback-action-dispatcher.d.ts.map +1 -1
  27. package/lib/base/feedback/feedback-action-dispatcher.js +27 -2
  28. package/lib/base/feedback/feedback-action-dispatcher.js.map +1 -1
  29. package/lib/base/feedback/feedback-command.d.ts +9 -4
  30. package/lib/base/feedback/feedback-command.d.ts.map +1 -1
  31. package/lib/base/feedback/feedback-command.js +14 -3
  32. package/lib/base/feedback/feedback-command.js.map +1 -1
  33. package/lib/base/feedback/index.d.ts +2 -1
  34. package/lib/base/feedback/index.d.ts.map +1 -1
  35. package/lib/base/feedback/index.js +2 -1
  36. package/lib/base/feedback/index.js.map +1 -1
  37. package/lib/base/feedback/set-model-command.d.ts +25 -0
  38. package/lib/base/feedback/set-model-command.d.ts.map +1 -0
  39. package/lib/base/feedback/set-model-command.js +65 -0
  40. package/lib/base/feedback/set-model-command.js.map +1 -0
  41. package/lib/base/feedback/update-model-command.d.ts +17 -6
  42. package/lib/base/feedback/update-model-command.d.ts.map +1 -1
  43. package/lib/base/feedback/update-model-command.js +9 -29
  44. package/lib/base/feedback/update-model-command.js.map +1 -1
  45. package/lib/base/index.d.ts +2 -1
  46. package/lib/base/index.d.ts.map +1 -1
  47. package/lib/base/index.js +2 -1
  48. package/lib/base/index.js.map +1 -1
  49. package/lib/base/model/diagram-loader.d.ts +12 -7
  50. package/lib/base/model/diagram-loader.d.ts.map +1 -1
  51. package/lib/base/model/diagram-loader.js +10 -17
  52. package/lib/base/model/diagram-loader.js.map +1 -1
  53. package/lib/base/model/glsp-model-source.d.ts +1 -1
  54. package/lib/base/model/glsp-model-source.js +1 -1
  55. package/lib/base/ranked.d.ts +11 -1
  56. package/lib/base/ranked.d.ts.map +1 -1
  57. package/lib/base/ranked.js +7 -1
  58. package/lib/base/ranked.js.map +1 -1
  59. package/lib/base/selection-service.d.ts +9 -8
  60. package/lib/base/selection-service.d.ts.map +1 -1
  61. package/lib/base/selection-service.js +11 -14
  62. package/lib/base/selection-service.js.map +1 -1
  63. package/lib/base/selection-service.spec.js +5 -1
  64. package/lib/base/selection-service.spec.js.map +1 -1
  65. package/lib/base/tool-manager/tool-manager.d.ts +10 -8
  66. package/lib/base/tool-manager/tool-manager.d.ts.map +1 -1
  67. package/lib/base/tool-manager/tool-manager.js +25 -22
  68. package/lib/base/tool-manager/tool-manager.js.map +1 -1
  69. package/lib/base/ui-extension-registry.d.ts +23 -0
  70. package/lib/base/ui-extension-registry.d.ts.map +1 -0
  71. package/lib/base/ui-extension-registry.js +51 -0
  72. package/lib/base/ui-extension-registry.js.map +1 -0
  73. package/lib/base/view/key-tool.d.ts +21 -2
  74. package/lib/base/view/key-tool.d.ts.map +1 -1
  75. package/lib/base/view/key-tool.js +21 -3
  76. package/lib/base/view/key-tool.js.map +1 -1
  77. package/lib/base/view/mouse-tool.d.ts +20 -3
  78. package/lib/base/view/mouse-tool.d.ts.map +1 -1
  79. package/lib/base/view/mouse-tool.js +9 -5
  80. package/lib/base/view/mouse-tool.js.map +1 -1
  81. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts +6 -4
  82. package/lib/features/bounds/glsp-hidden-bounds-updater.d.ts.map +1 -1
  83. package/lib/features/bounds/glsp-hidden-bounds-updater.js +20 -3
  84. package/lib/features/bounds/glsp-hidden-bounds-updater.js.map +1 -1
  85. package/lib/features/bounds/local-bounds.d.ts +8 -4
  86. package/lib/features/bounds/local-bounds.d.ts.map +1 -1
  87. package/lib/features/bounds/local-bounds.js +9 -5
  88. package/lib/features/bounds/local-bounds.js.map +1 -1
  89. package/lib/features/bounds/set-bounds-feedback-command.d.ts +2 -2
  90. package/lib/features/bounds/set-bounds-feedback-command.d.ts.map +1 -1
  91. package/lib/features/bounds/set-bounds-feedback-command.js +5 -3
  92. package/lib/features/bounds/set-bounds-feedback-command.js.map +1 -1
  93. package/lib/features/change-bounds/position-snapper.d.ts +1 -1
  94. package/lib/features/change-bounds/position-snapper.js +1 -1
  95. package/lib/features/element-template/add-template-element.d.ts +1 -1
  96. package/lib/features/element-template/add-template-element.d.ts.map +1 -1
  97. package/lib/features/element-template/add-template-element.js +6 -5
  98. package/lib/features/element-template/add-template-element.js.map +1 -1
  99. package/lib/features/helper-lines/helper-line-feedback.d.ts +1 -1
  100. package/lib/features/helper-lines/helper-line-feedback.d.ts.map +1 -1
  101. package/lib/features/helper-lines/helper-line-feedback.js +9 -3
  102. package/lib/features/helper-lines/helper-line-feedback.js.map +1 -1
  103. package/lib/features/helper-lines/helper-line-manager-default.d.ts +1 -1
  104. package/lib/features/helper-lines/helper-line-manager-default.js +1 -1
  105. package/lib/features/helper-lines/helper-line-manager.d.ts +1 -1
  106. package/lib/features/hints/type-hint-provider.d.ts +17 -2
  107. package/lib/features/hints/type-hint-provider.d.ts.map +1 -1
  108. package/lib/features/hints/type-hint-provider.js +13 -13
  109. package/lib/features/hints/type-hint-provider.js.map +1 -1
  110. package/lib/features/navigation/navigation-action-handler.d.ts +15 -0
  111. package/lib/features/navigation/navigation-action-handler.d.ts.map +1 -1
  112. package/lib/features/navigation/navigation-action-handler.js +2 -2
  113. package/lib/features/navigation/navigation-action-handler.js.map +1 -1
  114. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.d.ts +1 -1
  115. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js +1 -1
  116. package/lib/features/tools/marquee-selection/marquee-behavior.spec.d.ts +1 -1
  117. package/lib/features/tools/marquee-selection/marquee-behavior.spec.js +1 -1
  118. package/lib/features/validation/validate.d.ts +20 -2
  119. package/lib/features/validation/validate.d.ts.map +1 -1
  120. package/lib/features/validation/validate.js +14 -11
  121. package/lib/features/validation/validate.js.map +1 -1
  122. package/lib/utils/gmodel-util.d.ts +2 -1
  123. package/lib/utils/gmodel-util.d.ts.map +1 -1
  124. package/lib/utils/gmodel-util.js +15 -5
  125. package/lib/utils/gmodel-util.js.map +1 -1
  126. package/lib/utils/html-utils.js +1 -1
  127. package/package.json +7 -6
  128. package/src/base/action-dispatcher.spec.ts +5 -4
  129. package/src/base/action-dispatcher.ts +20 -4
  130. package/src/base/action-handler-registry.ts +24 -3
  131. package/src/base/command-stack.ts +17 -29
  132. package/src/base/default.module.ts +22 -4
  133. package/src/base/editor-context-service.ts +61 -16
  134. package/src/base/feedback/feedback-action-dispatcher.ts +50 -2
  135. package/src/base/feedback/feedback-command.ts +16 -5
  136. package/src/base/feedback/index.ts +3 -1
  137. package/src/base/feedback/set-model-command.ts +45 -0
  138. package/src/base/feedback/update-model-command.ts +9 -46
  139. package/src/base/index.ts +2 -1
  140. package/src/base/model/diagram-loader.ts +21 -14
  141. package/src/base/model/glsp-model-source.ts +1 -1
  142. package/src/base/ranked.ts +15 -1
  143. package/src/base/selection-service.spec.ts +8 -2
  144. package/src/base/selection-service.ts +22 -21
  145. package/src/base/tool-manager/tool-manager.ts +27 -23
  146. package/src/base/ui-extension-registry.ts +33 -0
  147. package/src/base/view/key-tool.ts +16 -4
  148. package/src/base/view/mouse-tool.ts +23 -6
  149. package/src/features/bounds/glsp-hidden-bounds-updater.ts +27 -5
  150. package/src/features/bounds/local-bounds.ts +24 -7
  151. package/src/features/bounds/set-bounds-feedback-command.ts +5 -3
  152. package/src/features/change-bounds/position-snapper.ts +1 -1
  153. package/src/features/element-template/add-template-element.ts +6 -5
  154. package/src/features/helper-lines/helper-line-feedback.ts +9 -3
  155. package/src/features/helper-lines/helper-line-manager-default.ts +1 -1
  156. package/src/features/helper-lines/helper-line-manager.ts +1 -1
  157. package/src/features/hints/type-hint-provider.ts +6 -6
  158. package/src/features/navigation/navigation-action-handler.ts +2 -2
  159. package/src/features/tools/change-bounds/change-bounds-tool-feedback.ts +1 -1
  160. package/src/features/tools/marquee-selection/marquee-behavior.spec.ts +1 -1
  161. package/src/features/validation/validate.ts +19 -12
  162. package/src/utils/gmodel-util.ts +16 -5
  163. package/src/utils/html-utils.ts +1 -1
  164. package/lib/tsconfig.tsbuildinfo +0 -1
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2020-2023 EclipseSource and others.
2
+ * Copyright (c) 2020-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,30 +13,50 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { inject, injectable, multiInject, optional, postConstruct, preDestroy } from 'inversify';
17
16
  import {
18
17
  Action,
18
+ AnyObject,
19
19
  Args,
20
+ CommandStack,
20
21
  Disposable,
21
22
  DisposableCollection,
22
23
  EditMode,
23
24
  EditorContext,
24
25
  Emitter,
25
26
  Event,
27
+ GModelElement,
28
+ GModelRoot,
26
29
  IActionHandler,
30
+ LazyInjector,
27
31
  MaybePromise,
28
32
  MousePositionTracker,
29
- GModelElement,
30
- GModelRoot,
31
33
  SetDirtyStateAction,
32
34
  SetEditModeAction,
33
35
  TYPES,
34
36
  ValueChange
35
37
  } from '@eclipse-glsp/sprotty';
38
+ import { inject, injectable, postConstruct, preDestroy } from 'inversify';
36
39
  import { GLSPActionDispatcher } from './action-dispatcher';
37
40
  import { IDiagramOptions, IDiagramStartup } from './model/diagram-loader';
38
41
  import { SelectionService } from './selection-service';
39
42
 
43
+ /**
44
+ * A hook to listen for model root changes. Will be called after a server update
45
+ * has been processed
46
+ */
47
+ export interface IGModelRootListener {
48
+ modelRootChanged(root: Readonly<GModelRoot>): void;
49
+ }
50
+
51
+ /**
52
+ * @deprecated Use {@link IGModelRootListener} instead
53
+ */
54
+ export type ISModelRootListener = IGModelRootListener;
55
+
56
+ /**
57
+ * A hook to listen for edit mode changes. Will be after the {@link EditorContextService}
58
+ * has handled the {@link SetEditModeAction}.
59
+ */
40
60
  export interface IEditModeListener {
41
61
  editModeChanged(newValue: string, oldValue: string): void;
42
62
  }
@@ -62,13 +82,12 @@ export class EditorContextService implements IActionHandler, Disposable, IDiagra
62
82
  @inject(MousePositionTracker)
63
83
  protected mousePositionTracker: MousePositionTracker;
64
84
 
85
+ @inject(LazyInjector)
86
+ protected lazyInjector: LazyInjector;
87
+
65
88
  @inject(TYPES.IDiagramOptions)
66
89
  protected diagramOptions: IDiagramOptions;
67
90
 
68
- @multiInject(TYPES.IEditModeListener)
69
- @optional()
70
- protected editModeListeners: IEditModeListener[] = [];
71
-
72
91
  @inject(GLSPActionDispatcher)
73
92
  protected actionDispatcher: GLSPActionDispatcher;
74
93
 
@@ -84,15 +103,27 @@ export class EditorContextService implements IActionHandler, Disposable, IDiagra
84
103
  return this.onDirtyStateChangedEmitter.event;
85
104
  }
86
105
 
106
+ protected _modelRoot?: Readonly<GModelRoot>;
107
+ protected onModelRootChangedEmitter = new Emitter<Readonly<GModelRoot>>();
108
+ get onModelRootChanged(): Event<Readonly<GModelRoot>> {
109
+ return this.onModelRootChangedEmitter.event;
110
+ }
111
+
87
112
  protected toDispose = new DisposableCollection();
88
113
 
89
114
  @postConstruct()
90
115
  protected initialize(): void {
91
116
  this._editMode = this.diagramOptions.editMode ?? EditMode.EDITABLE;
92
117
  this.toDispose.push(this.onEditModeChangedEmitter, this.onDirtyStateChangedEmitter);
93
- this.editModeListeners.forEach(listener =>
94
- this.onEditModeChanged(change => listener.editModeChanged(change.newValue, change.oldValue))
95
- );
118
+ }
119
+
120
+ preLoadDiagram(): MaybePromise<void> {
121
+ this.lazyInjector.getAll<IGModelRootListener>(TYPES.IGModelRootListener).forEach(listener => {
122
+ this.onModelRootChanged(event => listener.modelRootChanged(event));
123
+ });
124
+ this.lazyInjector.getAll<IEditModeListener>(TYPES.IEditModeListener).forEach(listener => {
125
+ this.onEditModeChanged(event => listener.editModeChanged(event.newValue, event.oldValue));
126
+ });
96
127
  }
97
128
 
98
129
  @preDestroy()
@@ -116,6 +147,21 @@ export class EditorContextService implements IActionHandler, Disposable, IDiagra
116
147
  };
117
148
  }
118
149
 
150
+ /**
151
+ * Notifies the service about a model root change. This method should not be called
152
+ * directly. It is called by the `CommandStack` after a model update has been processed.
153
+ * @throws an error if the notifier is not a `CommandStack`
154
+ * @param root the new model root
155
+ * @param notifier the object that triggered the model root change
156
+ */
157
+ notifyModelRootChanged(root: Readonly<GModelRoot>, notifier: AnyObject): void {
158
+ if (!(notifier instanceof CommandStack)) {
159
+ throw new Error('Invalid model root change notification. Notifier is not an instance of `CommandStack`.');
160
+ }
161
+ this._modelRoot = root;
162
+ this.onModelRootChangedEmitter.fire(root);
163
+ }
164
+
119
165
  handle(action: Action): void {
120
166
  if (SetEditModeAction.is(action)) {
121
167
  this.handleSetEditModeAction(action);
@@ -154,7 +200,10 @@ export class EditorContextService implements IActionHandler, Disposable, IDiagra
154
200
  }
155
201
 
156
202
  get modelRoot(): Readonly<GModelRoot> {
157
- return this.selectionService.getModelRoot();
203
+ if (!this._modelRoot) {
204
+ throw new Error('Model root not available yet');
205
+ }
206
+ return this._modelRoot;
158
207
  }
159
208
 
160
209
  get selectedElements(): Readonly<GModelElement>[] {
@@ -168,10 +217,6 @@ export class EditorContextService implements IActionHandler, Disposable, IDiagra
168
217
  get isDirty(): boolean {
169
218
  return this._isDirty;
170
219
  }
171
-
172
- postRequestModel(): MaybePromise<void> {
173
- this.actionDispatcher.dispatch(SetEditModeAction.create(this.editMode));
174
- }
175
220
  }
176
221
 
177
222
  export type EditorContextServiceProvider = () => Promise<EditorContextService>;
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2023 EclipseSource and others.
2
+ * Copyright (c) 2019-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,8 +13,21 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
+ import {
17
+ Action,
18
+ ActionHandlerRegistry,
19
+ Command,
20
+ CommandActionHandler,
21
+ CommandExecutionContext,
22
+ Disposable,
23
+ IActionDispatcher,
24
+ ICommand,
25
+ ILogger,
26
+ TYPES,
27
+ toTypeGuard
28
+ } from '@eclipse-glsp/sprotty';
16
29
  import { inject, injectable } from 'inversify';
17
- import { Action, Disposable, IActionDispatcher, ILogger, TYPES } from '@eclipse-glsp/sprotty';
30
+ import { getFeedbackRank } from './feedback-command';
18
31
 
19
32
  export interface IFeedbackEmitter {}
20
33
 
@@ -57,6 +70,16 @@ export interface IFeedbackActionDispatcher {
57
70
  * Retrieve all `actions` sent out by currently registered `feedbackEmitter`.
58
71
  */
59
72
  getRegisteredFeedback(): Action[];
73
+
74
+ /**
75
+ * Retrieves all commands based on the registered feedback actions, ordered by their rank (lowest rank first).
76
+ */
77
+ getFeedbackCommands(): Command[];
78
+
79
+ /**
80
+ * Applies all current feedback commands to the given command execution context.
81
+ */
82
+ applyFeedbackCommands(context: CommandExecutionContext): Promise<void>;
60
83
  }
61
84
 
62
85
  @injectable()
@@ -66,6 +89,8 @@ export class FeedbackActionDispatcher implements IFeedbackActionDispatcher {
66
89
  @inject(TYPES.IActionDispatcherProvider) protected actionDispatcher: () => Promise<IActionDispatcher>;
67
90
  @inject(TYPES.ILogger) protected logger: ILogger;
68
91
 
92
+ @inject(ActionHandlerRegistry) protected actionHandlerRegistry: ActionHandlerRegistry;
93
+
69
94
  registerFeedback(feedbackEmitter: IFeedbackEmitter, feedbackActions: Action[], cleanupActions?: Action[] | undefined): Disposable {
70
95
  if (feedbackActions.length > 0) {
71
96
  this.registeredFeedback.set(feedbackEmitter, feedbackActions);
@@ -97,6 +122,29 @@ export class FeedbackActionDispatcher implements IFeedbackActionDispatcher {
97
122
  return result;
98
123
  }
99
124
 
125
+ getFeedbackCommands(): Command[] {
126
+ return this.getRegisteredFeedback()
127
+ .flatMap(action => this.actionToCommands(action))
128
+ .sort((left, right) => getFeedbackRank(left) - getFeedbackRank(right));
129
+ }
130
+
131
+ async applyFeedbackCommands(context: CommandExecutionContext): Promise<void> {
132
+ const feedbackCommands = this.getFeedbackCommands() ?? [];
133
+ if (feedbackCommands?.length > 0) {
134
+ const results = feedbackCommands.map(command => command.execute(context));
135
+ await Promise.all(results);
136
+ }
137
+ }
138
+
139
+ protected actionToCommands(action: Action): ICommand[] {
140
+ return (
141
+ this.actionHandlerRegistry
142
+ .get(action.kind)
143
+ .filter(toTypeGuard(CommandActionHandler))
144
+ .map(handler => handler.handle(action)) ?? []
145
+ );
146
+ }
147
+
100
148
  protected async dispatchFeedback(actions: Action[], feedbackEmitter: IFeedbackEmitter): Promise<void> {
101
149
  try {
102
150
  const actionDispatcher = await this.actionDispatcher();
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2023 EclipseSource and others.
2
+ * Copyright (c) 2019-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,11 +13,16 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Command, CommandExecutionContext, CommandReturn } from '@eclipse-glsp/sprotty';
16
+ /* eslint-disable deprecation/deprecation */
17
+ import { Command, CommandExecutionContext, CommandReturn, ICommand } from '@eclipse-glsp/sprotty';
18
+ import { Ranked } from '../ranked';
17
19
 
18
- export abstract class FeedbackCommand extends Command {
19
- // used by the `FeedbackAwareUpdateModelCommand`
20
- readonly priority: number = 0;
20
+ export abstract class FeedbackCommand extends Command implements Ranked {
21
+ /** @deprecated Use rank instead. Please note that a lower rank implies higher priority, so the order is reversed. */
22
+ readonly priority?: number = 0;
23
+
24
+ // backwards compatibility: convert any existing priority to an equivalent rank
25
+ readonly rank: number = this.priority ? -this.priority : Ranked.DEFAULT_RANK;
21
26
 
22
27
  undo(context: CommandExecutionContext): CommandReturn {
23
28
  return context.root;
@@ -27,3 +32,9 @@ export abstract class FeedbackCommand extends Command {
27
32
  return context.root;
28
33
  }
29
34
  }
35
+
36
+ /** Used for backwards compatibility, otherwise use Ranked.getRank or Ranked sort functions. */
37
+ export function getFeedbackRank(command: ICommand): number {
38
+ const feedbackCommand = command as Partial<FeedbackCommand>;
39
+ return feedbackCommand?.priority ? -feedbackCommand.priority : feedbackCommand.rank ?? Ranked.DEFAULT_RANK;
40
+ }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -16,4 +16,6 @@
16
16
  export * from './css-feedback';
17
17
  export * from './feedback-action-dispatcher';
18
18
  export * from './feedback-command';
19
+ export * from './set-model-command';
19
20
  export * from './update-model-command';
21
+
@@ -0,0 +1,45 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2024 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+ import { CommandExecutionContext, GModelRoot, ILogger, SetModelAction, SetModelCommand, TYPES } from '@eclipse-glsp/sprotty';
17
+ import { inject, injectable, optional } from 'inversify';
18
+ import { IFeedbackActionDispatcher } from './feedback-action-dispatcher';
19
+
20
+ @injectable()
21
+ export class FeedbackAwareSetModelCommand extends SetModelCommand {
22
+ @inject(TYPES.ILogger)
23
+ protected logger: ILogger;
24
+
25
+ @inject(TYPES.IFeedbackActionDispatcher)
26
+ @optional()
27
+ protected feedbackActionDispatcher?: IFeedbackActionDispatcher;
28
+
29
+ constructor(@inject(TYPES.Action) action: SetModelAction) {
30
+ super(action);
31
+ }
32
+
33
+ override execute(context: CommandExecutionContext): GModelRoot {
34
+ const root = super.execute(context);
35
+ this.applyFeedback(root, context);
36
+ return root;
37
+ }
38
+
39
+ protected applyFeedback(newRoot: GModelRoot, context: CommandExecutionContext): void {
40
+ // Create a temporary context which defines the `newRoot` as `root`
41
+ // This way we do not corrupt the redo/undo behavior of the super class
42
+ const tempContext: CommandExecutionContext = { ...context, root: newRoot };
43
+ this.feedbackActionDispatcher?.applyFeedbackCommands(tempContext);
44
+ }
45
+ }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2023 EclipseSource and others.
2
+ * Copyright (c) 2019-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,25 +13,20 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { inject, injectable, optional } from 'inversify';
17
16
  import {
18
- ActionHandlerRegistry,
19
17
  Animation,
20
- Command,
21
- CommandActionHandler,
22
18
  CommandExecutionContext,
23
19
  CommandReturn,
20
+ GModelRoot,
24
21
  ILogger,
25
22
  MorphEdgesAnimation,
26
- GModelRoot,
27
23
  TYPES,
28
24
  UpdateAnimationData,
29
25
  UpdateModelAction,
30
- UpdateModelCommand,
31
- toTypeGuard
26
+ UpdateModelCommand
32
27
  } from '@eclipse-glsp/sprotty';
28
+ import { inject, injectable, optional } from 'inversify';
33
29
  import { IFeedbackActionDispatcher } from './feedback-action-dispatcher';
34
- import { FeedbackCommand } from './feedback-command';
35
30
 
36
31
  /**
37
32
  * A special {@link UpdateModelCommand} that retrieves all registered {@link Action}s from the {@link IFeedbackActionDispatcher}
@@ -47,50 +42,18 @@ export class FeedbackAwareUpdateModelCommand extends UpdateModelCommand {
47
42
  @optional()
48
43
  protected feedbackActionDispatcher: IFeedbackActionDispatcher;
49
44
 
50
- protected actionHandlerRegistry?: ActionHandlerRegistry;
51
-
52
- constructor(
53
- @inject(TYPES.Action) action: UpdateModelAction,
54
- @inject(TYPES.ActionHandlerRegistryProvider)
55
- actionHandlerRegistryProvider: () => Promise<ActionHandlerRegistry>
56
- ) {
45
+ constructor(@inject(TYPES.Action) action: UpdateModelAction) {
57
46
  super({ animate: true, ...action });
58
- actionHandlerRegistryProvider().then(registry => (this.actionHandlerRegistry = registry));
59
47
  }
60
48
 
61
49
  protected override performUpdate(oldRoot: GModelRoot, newRoot: GModelRoot, context: CommandExecutionContext): CommandReturn {
62
- if (this.feedbackActionDispatcher && this.actionHandlerRegistry) {
63
- // Create a temporary context which defines the `newRoot` as `root`
64
- // This way we do not corrupt the redo/undo behavior of the super class
65
- const tempContext: CommandExecutionContext = {
66
- ...context,
67
- root: newRoot
68
- };
69
-
70
- const feedbackCommands = this.getFeedbackCommands(this.actionHandlerRegistry);
71
- feedbackCommands.forEach(command => command.execute(tempContext));
72
- }
73
-
50
+ // Create a temporary context which defines the `newRoot` as `root`
51
+ // This way we do not corrupt the redo/undo behavior of the super class
52
+ const tempContext: CommandExecutionContext = { ...context, root: newRoot };
53
+ this.feedbackActionDispatcher?.applyFeedbackCommands(tempContext);
74
54
  return super.performUpdate(oldRoot, newRoot, context);
75
55
  }
76
56
 
77
- protected getFeedbackCommands(registry: ActionHandlerRegistry): Command[] {
78
- const result: Command[] = [];
79
- this.feedbackActionDispatcher.getRegisteredFeedback().forEach(action => {
80
- const commands = registry
81
- .get(action.kind)
82
- .filter<CommandActionHandler>(toTypeGuard(CommandActionHandler))
83
- .map(handler => handler.handle(action));
84
- result.push(...commands);
85
- });
86
- // sort commands descanting by priority
87
- return result.sort((a, b) => this.getPriority(b) - this.getPriority(a));
88
- }
89
-
90
- protected getPriority(command: Partial<FeedbackCommand>): number {
91
- return command.priority ?? 0;
92
- }
93
-
94
57
  // Override the `createAnimations` implementation and remove the animation for edge morphing. Otherwise routing & reconnect
95
58
  // handles flicker after each server update.
96
59
  protected override createAnimations(data: UpdateAnimationData, root: GModelRoot, context: CommandExecutionContext): Animation[] {
package/src/base/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -28,4 +28,5 @@ export * from './ranked';
28
28
  export * from './selection-clearing-mouse-listener';
29
29
  export * from './selection-service';
30
30
  export * from './tool-manager';
31
+ export * from './ui-extension-registry';
31
32
  export * from './view';
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -21,6 +21,7 @@ import {
21
21
  EMPTY_ROOT,
22
22
  GLSPClient,
23
23
  InitializeParameters,
24
+ LazyInjector,
24
25
  MaybePromise,
25
26
  RequestModelAction,
26
27
  SetModelAction,
@@ -28,7 +29,7 @@ import {
28
29
  TYPES,
29
30
  hasNumberProp
30
31
  } from '@eclipse-glsp/sprotty';
31
- import { inject, injectable, multiInject, optional, postConstruct } from 'inversify';
32
+ import { inject, injectable } from 'inversify';
32
33
  import { GLSPActionDispatcher } from '../action-dispatcher';
33
34
  import { Ranked } from '../ranked';
34
35
  import { GLSPModelSource } from './glsp-model-source';
@@ -69,22 +70,27 @@ export interface IDiagramOptions {
69
70
  */
70
71
  export interface IDiagramStartup extends Partial<Ranked> {
71
72
  /**
72
- * Hook for services that should be executed before the underlying GLSP client is configured and the server is initialized.
73
+ * Hook for services that want to execute code before the diagram loading routine is started. This is the
74
+ * first hook that is invoked directly after {@link DiagramLoader.load} is called.
75
+ */
76
+ preLoadDiagram?(): MaybePromise<void>;
77
+ /**
78
+ * Hook for services that want to execute code before the underlying GLSP client is configured and the server is initialized.
73
79
  */
74
80
  preInitialize?(): MaybePromise<void>;
75
81
  /**
76
- * Hook for services that should be executed before the initial model loading request (i.e. `RequestModelAction`) but
82
+ * Hook for services that want to execute code before the initial model loading request (i.e. `RequestModelAction`) but
77
83
  * after the underlying GLSP client has been configured and the server is initialized.
78
84
  */
79
85
  preRequestModel?(): MaybePromise<void>;
80
86
  /**
81
- * Hook for services that should be executed after the initial model loading request (i.e. `RequestModelAction`).
87
+ * Hook for services that want to execute code after the initial model loading request (i.e. `RequestModelAction`).
82
88
  * Note that this hook is invoked directly after the `RequestModelAction` has been dispatched. It does not necessarily wait
83
89
  * until the client-server update roundtrip is completed. If you need to wait until the diagram is fully initialized use the
84
90
  * {@link postModelInitialization} hook.
85
91
  */
86
92
  postRequestModel?(): MaybePromise<void>;
87
- /* Hook for services that should be executed after the diagram model is fully initialized
93
+ /* Hook for services that want to execute code after the diagram model is fully initialized
88
94
  * (i.e. `ModelInitializationConstraint` is completed).
89
95
  */
90
96
  postModelInitialization?(): MaybePromise<void>;
@@ -95,7 +101,8 @@ export namespace IDiagramStartup {
95
101
  return (
96
102
  AnyObject.is(object) &&
97
103
  hasNumberProp(object, 'rank', true) &&
98
- ('preInitialize' in object ||
104
+ ('preLoadDiagram' in object ||
105
+ 'preInitialize' in object ||
99
106
  'preRequestModel' in object ||
100
107
  'postRequestModel' in object ||
101
108
  'postModelInitialization' in object)
@@ -144,22 +151,22 @@ export class DiagramLoader {
144
151
  @inject(GLSPActionDispatcher)
145
152
  protected actionDispatcher: GLSPActionDispatcher;
146
153
 
147
- @multiInject(TYPES.IDiagramStartup)
148
- @optional()
149
- protected diagramStartups: IDiagramStartup[] = [];
150
-
151
154
  @inject(GLSPModelSource)
152
155
  protected modelSource: GLSPModelSource;
153
156
 
154
157
  @inject(ModelInitializationConstraint)
155
158
  protected modelInitializationConstraint: ModelInitializationConstraint;
156
159
 
157
- @postConstruct()
158
- protected postConstruct(): void {
159
- this.diagramStartups.sort((a, b) => Ranked.getRank(a) - Ranked.getRank(b));
160
+ @inject(LazyInjector)
161
+ protected lazyInjector: LazyInjector;
162
+
163
+ get diagramStartups(): IDiagramStartup[] {
164
+ return this.lazyInjector.getAll<IDiagramStartup>(TYPES.IDiagramStartup);
160
165
  }
161
166
 
162
167
  async load(options: DiagramLoadingOptions = {}): Promise<void> {
168
+ this.diagramStartups.sort(Ranked.sort);
169
+ await this.invokeStartupHook('preLoadDiagram');
163
170
  const resolvedOptions: ResolvedDiagramLoadingOptions = {
164
171
  requestModelOptions: {
165
172
  sourceUri: this.options.sourceUri ?? '',
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2019-2023 EclipseSource and others.
2
+ * Copyright (c) 2019-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -21,11 +21,16 @@ import { AnyObject, hasNumberProp } from '@eclipse-glsp/sprotty';
21
21
  * orderable by a type or rank/priority.
22
22
  */
23
23
  export interface Ranked {
24
+ /**
25
+ * A rank implies the position of this element within a sequence of other ranked elements.
26
+ * A lower rank implies a position earlier in the list.
27
+ */
24
28
  rank: number;
25
29
  }
26
30
 
27
31
  export namespace Ranked {
28
32
  export const DEFAULT_RANK = 0;
33
+
29
34
  export function is(object: unknown): object is Ranked {
30
35
  return AnyObject.is(object) && hasNumberProp(object, 'rank');
31
36
  }
@@ -39,4 +44,13 @@ export namespace Ranked {
39
44
  export function getRank(object: unknown): number {
40
45
  return is(object) ? object.rank : DEFAULT_RANK;
41
46
  }
47
+
48
+ /** Sort function for lowest rank first. */
49
+ export const sortAsc = (left: unknown, right: unknown): number => getRank(left) - getRank(right);
50
+
51
+ /** Sort function for highest rank first. */
52
+ export const sortDesc = (left: unknown, right: unknown): number => getRank(right) - getRank(left);
53
+
54
+ /** Default sort function for rank: Lowest rank first */
55
+ export const sort = sortAsc;
42
56
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2020-2023 EclipseSource and others.
2
+ * Copyright (c) 2020-2024 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Action, Disposable, GModelRoot, GNode, TYPES, initializeContainer } from '@eclipse-glsp/sprotty';
16
+ import { Action, Command, CommandExecutionContext, Disposable, GModelRoot, GNode, TYPES, initializeContainer } from '@eclipse-glsp/sprotty';
17
17
  import { AssertionError, expect } from 'chai';
18
18
  import { Container, injectable } from 'inversify';
19
19
  import * as sinon from 'sinon';
@@ -44,6 +44,12 @@ class MockFeedbackActionDispatcher implements IFeedbackActionDispatcher {
44
44
  const actions = this.getRegisteredFeedback();
45
45
  return actions.length === 1 ? (actions[0] as SelectFeedbackAction) : undefined;
46
46
  }
47
+
48
+ getFeedbackCommands(): Command[] {
49
+ return [];
50
+ }
51
+
52
+ async applyFeedbackCommands(context: CommandExecutionContext): Promise<void> {}
47
53
  }
48
54
 
49
55
  class MockSelectionListener implements ISelectionListener {