@eclipse-glsp/client 2.2.0-next.335 → 2.2.0-next.337
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.
- package/css/ghost-element.css +7 -0
- package/lib/base/default.module.d.ts.map +1 -1
- package/lib/base/default.module.js +1 -2
- package/lib/base/default.module.js.map +1 -1
- package/lib/base/drag-aware-mouse-listener.d.ts +4 -1
- package/lib/base/drag-aware-mouse-listener.d.ts.map +1 -1
- package/lib/base/drag-aware-mouse-listener.js +12 -2
- package/lib/base/drag-aware-mouse-listener.js.map +1 -1
- package/lib/base/feedback/feedback-action-dispatcher-default.d.ts +34 -0
- package/lib/base/feedback/feedback-action-dispatcher-default.d.ts.map +1 -0
- package/lib/base/feedback/feedback-action-dispatcher-default.js +120 -0
- package/lib/base/feedback/feedback-action-dispatcher-default.js.map +1 -0
- package/lib/base/feedback/feedback-action-dispatcher.d.ts +2 -17
- package/lib/base/feedback/feedback-action-dispatcher.d.ts.map +1 -1
- package/lib/base/feedback/feedback-action-dispatcher.js +1 -100
- package/lib/base/feedback/feedback-action-dispatcher.js.map +1 -1
- package/lib/base/feedback/{feeback-emitter.d.ts → feedback-emitter.d.ts} +8 -1
- package/lib/base/feedback/feedback-emitter.d.ts.map +1 -0
- package/lib/base/feedback/{feeback-emitter.js → feedback-emitter.js} +21 -6
- package/lib/base/feedback/feedback-emitter.js.map +1 -0
- package/lib/base/feedback/index.d.ts +2 -1
- package/lib/base/feedback/index.d.ts.map +1 -1
- package/lib/base/feedback/index.js +2 -1
- package/lib/base/feedback/index.js.map +1 -1
- package/lib/features/accessibility/view-key-tools/movement-key-tool.d.ts.map +1 -1
- package/lib/features/accessibility/view-key-tools/movement-key-tool.js +1 -1
- package/lib/features/accessibility/view-key-tools/movement-key-tool.js.map +1 -1
- package/lib/features/change-bounds/model.d.ts +5 -1
- package/lib/features/change-bounds/model.d.ts.map +1 -1
- package/lib/features/change-bounds/model.js +36 -10
- package/lib/features/change-bounds/model.js.map +1 -1
- package/lib/features/change-bounds/movement-restrictor.d.ts +1 -0
- package/lib/features/change-bounds/movement-restrictor.d.ts.map +1 -1
- package/lib/features/change-bounds/movement-restrictor.js +8 -9
- package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
- package/lib/features/copy-paste/copy-paste-standalone.d.ts.map +1 -1
- package/lib/features/copy-paste/copy-paste-standalone.js +0 -3
- package/lib/features/copy-paste/copy-paste-standalone.js.map +1 -1
- package/lib/features/debug/debug-bounds-decorator.d.ts.map +1 -1
- package/lib/features/debug/debug-bounds-decorator.js +6 -6
- package/lib/features/debug/debug-bounds-decorator.js.map +1 -1
- package/lib/features/debug/debug-module.js +1 -1
- package/lib/features/debug/debug-module.js.map +1 -1
- package/lib/features/element-template/mouse-tracking-element-position-listener.d.ts +6 -4
- package/lib/features/element-template/mouse-tracking-element-position-listener.d.ts.map +1 -1
- package/lib/features/element-template/mouse-tracking-element-position-listener.js +11 -12
- package/lib/features/element-template/mouse-tracking-element-position-listener.js.map +1 -1
- package/lib/features/grid/grid-module.d.ts.map +1 -1
- package/lib/features/grid/grid-module.js +1 -1
- package/lib/features/grid/grid-module.js.map +1 -1
- package/lib/features/helper-lines/helper-line-manager-default.d.ts +14 -2
- package/lib/features/helper-lines/helper-line-manager-default.d.ts.map +1 -1
- package/lib/features/helper-lines/helper-line-manager-default.js +56 -15
- package/lib/features/helper-lines/helper-line-manager-default.js.map +1 -1
- package/lib/features/hints/model.d.ts +5 -1
- package/lib/features/hints/model.d.ts.map +1 -1
- package/lib/features/hints/model.js.map +1 -1
- package/lib/features/select/select-mouse-listener.d.ts.map +1 -1
- package/lib/features/select/select-mouse-listener.js +1 -1
- package/lib/features/select/select-mouse-listener.js.map +1 -1
- package/lib/features/tool-palette/tool-palette.d.ts.map +1 -1
- package/lib/features/tool-palette/tool-palette.js +2 -2
- package/lib/features/tool-palette/tool-palette.js.map +1 -1
- package/lib/features/tools/base-tools.d.ts +1 -1
- package/lib/features/tools/base-tools.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-manager.d.ts +11 -4
- package/lib/features/tools/change-bounds/change-bounds-manager.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-manager.js +46 -13
- package/lib/features/tools/change-bounds/change-bounds-manager.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-feedback.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js +3 -3
- package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-module.js +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-module.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts +2 -2
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js +3 -6
- package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool.d.ts +3 -2
- package/lib/features/tools/change-bounds/change-bounds-tool.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tool.js +7 -27
- package/lib/features/tools/change-bounds/change-bounds-tool.js.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tracker.d.ts +8 -2
- package/lib/features/tools/change-bounds/change-bounds-tracker.d.ts.map +1 -1
- package/lib/features/tools/change-bounds/change-bounds-tracker.js +22 -5
- package/lib/features/tools/change-bounds/change-bounds-tracker.js.map +1 -1
- package/lib/features/tools/edge-creation/edge-creation-tool.d.ts +4 -1
- package/lib/features/tools/edge-creation/edge-creation-tool.d.ts.map +1 -1
- package/lib/features/tools/edge-creation/edge-creation-tool.js +12 -10
- package/lib/features/tools/edge-creation/edge-creation-tool.js.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js +3 -3
- package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool.d.ts +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool.d.ts.map +1 -1
- package/lib/features/tools/edge-edit/edge-edit-tool.js +3 -3
- package/lib/features/tools/edge-edit/edge-edit-tool.js.map +1 -1
- package/lib/features/tools/node-creation/container-manager.d.ts +41 -0
- package/lib/features/tools/node-creation/container-manager.d.ts.map +1 -0
- package/lib/features/tools/node-creation/container-manager.js +73 -0
- package/lib/features/tools/node-creation/container-manager.js.map +1 -0
- package/lib/features/tools/node-creation/index.d.ts +3 -0
- package/lib/features/tools/node-creation/index.d.ts.map +1 -1
- package/lib/features/tools/node-creation/index.js +3 -0
- package/lib/features/tools/node-creation/index.js.map +1 -1
- package/lib/features/tools/node-creation/insert-indicator.d.ts +30 -0
- package/lib/features/tools/node-creation/insert-indicator.d.ts.map +1 -0
- package/lib/features/tools/node-creation/insert-indicator.js +40 -0
- package/lib/features/tools/node-creation/insert-indicator.js.map +1 -0
- package/lib/features/tools/node-creation/node-creation-module.d.ts.map +1 -1
- package/lib/features/tools/node-creation/node-creation-module.js +5 -0
- package/lib/features/tools/node-creation/node-creation-module.js.map +1 -1
- package/lib/features/tools/node-creation/node-creation-tool.d.ts +23 -14
- package/lib/features/tools/node-creation/node-creation-tool.d.ts.map +1 -1
- package/lib/features/tools/node-creation/node-creation-tool.js +79 -75
- package/lib/features/tools/node-creation/node-creation-tool.js.map +1 -1
- package/lib/features/tools/node-creation/node-creation-views.d.ts +25 -0
- package/lib/features/tools/node-creation/node-creation-views.d.ts.map +1 -0
- package/lib/features/tools/node-creation/node-creation-views.js +60 -0
- package/lib/features/tools/node-creation/node-creation-views.js.map +1 -0
- package/lib/utils/gmodel-util.d.ts +2 -0
- package/lib/utils/gmodel-util.d.ts.map +1 -1
- package/lib/utils/gmodel-util.js.map +1 -1
- package/lib/views/ggraph-view.d.ts.map +1 -1
- package/lib/views/ggraph-view.js +2 -2
- package/lib/views/ggraph-view.js.map +1 -1
- package/lib/views/glsp-projection-view.d.ts.map +1 -1
- package/lib/views/glsp-projection-view.js +2 -2
- package/lib/views/glsp-projection-view.js.map +1 -1
- package/package.json +3 -3
- package/src/base/default.module.ts +1 -2
- package/src/base/drag-aware-mouse-listener.ts +17 -1
- package/src/base/feedback/feedback-action-dispatcher-default.ts +119 -0
- package/src/base/feedback/feedback-action-dispatcher.ts +2 -106
- package/src/base/feedback/feedback-emitter.spec.ts +176 -0
- package/src/base/feedback/{feeback-emitter.ts → feedback-emitter.ts} +24 -5
- package/src/base/feedback/index.ts +2 -1
- package/src/base/selection-service.spec.ts +1 -1
- package/src/features/accessibility/view-key-tools/movement-key-tool.ts +1 -1
- package/src/features/change-bounds/model.ts +38 -13
- package/src/features/change-bounds/movement-restrictor.ts +11 -11
- package/src/features/copy-paste/copy-paste-standalone.ts +0 -3
- package/src/features/debug/debug-bounds-decorator.tsx +7 -7
- package/src/features/debug/debug-module.ts +1 -1
- package/src/features/element-template/mouse-tracking-element-position-listener.ts +14 -22
- package/src/features/grid/grid-module.ts +2 -2
- package/src/features/helper-lines/helper-line-manager-default.ts +66 -10
- package/src/features/hints/model.ts +6 -1
- package/src/features/hints/type-hint-provider.spec.ts +1 -1
- package/src/features/select/select-mouse-listener.ts +2 -2
- package/src/features/tool-palette/tool-palette.ts +2 -3
- package/src/features/tools/base-tools.ts +1 -1
- package/src/features/tools/change-bounds/change-bounds-manager.ts +71 -13
- package/src/features/tools/change-bounds/change-bounds-tool-feedback.ts +5 -2
- package/src/features/tools/change-bounds/change-bounds-tool-module.ts +1 -1
- package/src/features/tools/change-bounds/change-bounds-tool-move-feedback.ts +4 -8
- package/src/features/tools/change-bounds/change-bounds-tool.ts +9 -55
- package/src/features/tools/change-bounds/change-bounds-tracker.ts +26 -5
- package/src/features/tools/edge-creation/edge-creation-tool.ts +13 -6
- package/src/features/tools/edge-edit/edge-edit-tool-feedback.ts +1 -1
- package/src/features/tools/edge-edit/edge-edit-tool.ts +2 -3
- package/src/features/tools/node-creation/container-manager.ts +76 -0
- package/src/features/tools/node-creation/index.ts +3 -0
- package/src/features/tools/node-creation/insert-indicator.ts +41 -0
- package/src/features/tools/node-creation/node-creation-module.ts +13 -1
- package/src/features/tools/node-creation/node-creation-tool.ts +98 -90
- package/src/features/tools/node-creation/node-creation-views.tsx +49 -0
- package/src/utils/gmodel-util.ts +4 -1
- package/src/views/ggraph-view.tsx +3 -3
- package/src/views/glsp-projection-view.tsx +2 -3
- package/lib/base/feedback/feeback-emitter.d.ts.map +0 -1
- package/lib/base/feedback/feeback-emitter.js.map +0 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2019-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 {
|
|
17
|
+
Action,
|
|
18
|
+
ActionHandlerRegistry,
|
|
19
|
+
Command,
|
|
20
|
+
CommandActionHandler,
|
|
21
|
+
CommandExecutionContext,
|
|
22
|
+
Disposable,
|
|
23
|
+
GModelElement,
|
|
24
|
+
IActionDispatcher,
|
|
25
|
+
ICommand,
|
|
26
|
+
ILogger,
|
|
27
|
+
TYPES,
|
|
28
|
+
toTypeGuard
|
|
29
|
+
} from '@eclipse-glsp/sprotty';
|
|
30
|
+
import { inject, injectable } from 'inversify';
|
|
31
|
+
import { getFeedbackRank } from './feedback-command';
|
|
32
|
+
import { FeedbackEmitter } from './feedback-emitter';
|
|
33
|
+
import { IFeedbackActionDispatcher, IFeedbackEmitter, MaybeActions } from './feedback-action-dispatcher';
|
|
34
|
+
|
|
35
|
+
@injectable()
|
|
36
|
+
export class FeedbackActionDispatcher implements IFeedbackActionDispatcher {
|
|
37
|
+
protected registeredFeedback: Map<IFeedbackEmitter, Action[]> = new Map();
|
|
38
|
+
|
|
39
|
+
@inject(TYPES.IActionDispatcherProvider) protected actionDispatcher: () => Promise<IActionDispatcher>;
|
|
40
|
+
@inject(TYPES.ILogger) protected logger: ILogger;
|
|
41
|
+
|
|
42
|
+
@inject(ActionHandlerRegistry) protected actionHandlerRegistry: ActionHandlerRegistry;
|
|
43
|
+
|
|
44
|
+
registerFeedback(feedbackEmitter: IFeedbackEmitter, feedbackActions: Action[], cleanupActions?: MaybeActions): Disposable {
|
|
45
|
+
if (feedbackEmitter instanceof GModelElement) {
|
|
46
|
+
this.logger.log(
|
|
47
|
+
this,
|
|
48
|
+
// eslint-disable-next-line max-len
|
|
49
|
+
'GModelElements as feedback emitters are discouraged, as they usually change between model updates and are considered unstable.'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (feedbackActions.length > 0) {
|
|
53
|
+
this.registeredFeedback.set(feedbackEmitter, feedbackActions);
|
|
54
|
+
this.dispatchFeedback(feedbackActions, feedbackEmitter);
|
|
55
|
+
}
|
|
56
|
+
return Disposable.create(() => this.deregisterFeedback(feedbackEmitter, cleanupActions));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
deregisterFeedback(feedbackEmitter: IFeedbackEmitter, cleanupActions?: MaybeActions): void {
|
|
60
|
+
this.registeredFeedback.delete(feedbackEmitter);
|
|
61
|
+
const actions = MaybeActions.asArray(cleanupActions);
|
|
62
|
+
if (actions.length > 0) {
|
|
63
|
+
this.dispatchFeedback(actions, feedbackEmitter);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getRegisteredFeedback(): Action[] {
|
|
68
|
+
const result: Action[] = [];
|
|
69
|
+
this.registeredFeedback.forEach(actions => result.push(...actions));
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getRegisteredFeedbackEmitters(action: Action): IFeedbackEmitter[] {
|
|
74
|
+
const result: IFeedbackEmitter[] = [];
|
|
75
|
+
this.registeredFeedback.forEach((actions, emitter) => {
|
|
76
|
+
if (actions.includes(action)) {
|
|
77
|
+
result.push(emitter);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getFeedbackCommands(): Command[] {
|
|
84
|
+
return this.getRegisteredFeedback()
|
|
85
|
+
.flatMap(action => this.actionToCommands(action))
|
|
86
|
+
.sort((left, right) => getFeedbackRank(left) - getFeedbackRank(right));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async applyFeedbackCommands(context: CommandExecutionContext): Promise<void> {
|
|
90
|
+
const feedbackCommands = this.getFeedbackCommands() ?? [];
|
|
91
|
+
if (feedbackCommands?.length > 0) {
|
|
92
|
+
const results = feedbackCommands.map(command => command.execute(context));
|
|
93
|
+
await Promise.all(results);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected actionToCommands(action: Action): ICommand[] {
|
|
98
|
+
return (
|
|
99
|
+
this.actionHandlerRegistry
|
|
100
|
+
.get(action.kind)
|
|
101
|
+
.filter(toTypeGuard(CommandActionHandler))
|
|
102
|
+
.map(handler => handler.handle(action)) ?? []
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
createEmitter(): FeedbackEmitter {
|
|
107
|
+
return new FeedbackEmitter(this);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected async dispatchFeedback(actions: Action[], feedbackEmitter: IFeedbackEmitter): Promise<void> {
|
|
111
|
+
try {
|
|
112
|
+
const actionDispatcher = await this.actionDispatcher();
|
|
113
|
+
await actionDispatcher.dispatchAll(actions);
|
|
114
|
+
this.logger.info(this, `Dispatched feedback actions for ${feedbackEmitter}`);
|
|
115
|
+
} catch (reason) {
|
|
116
|
+
this.logger.error(this, 'Failed to dispatch feedback actions', reason);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -13,26 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
ActionHandlerRegistry,
|
|
19
|
-
Command,
|
|
20
|
-
CommandActionHandler,
|
|
21
|
-
CommandExecutionContext,
|
|
22
|
-
Disposable,
|
|
23
|
-
GModelElement,
|
|
24
|
-
IActionDispatcher,
|
|
25
|
-
ICommand,
|
|
26
|
-
ILogger,
|
|
27
|
-
MaybeFunction,
|
|
28
|
-
TYPES,
|
|
29
|
-
call,
|
|
30
|
-
asArray as toArray,
|
|
31
|
-
toTypeGuard
|
|
32
|
-
} from '@eclipse-glsp/sprotty';
|
|
33
|
-
import { inject, injectable } from 'inversify';
|
|
34
|
-
import { getFeedbackRank } from './feedback-command';
|
|
35
|
-
import { FeedbackEmitter } from './feeback-emitter';
|
|
16
|
+
import { Action, Command, CommandExecutionContext, Disposable, MaybeFunction, call, asArray as toArray } from '@eclipse-glsp/sprotty';
|
|
17
|
+
import { FeedbackEmitter } from './feedback-emitter';
|
|
36
18
|
|
|
37
19
|
export interface IFeedbackEmitter {}
|
|
38
20
|
|
|
@@ -104,89 +86,3 @@ export interface IFeedbackActionDispatcher {
|
|
|
104
86
|
*/
|
|
105
87
|
createEmitter(): FeedbackEmitter;
|
|
106
88
|
}
|
|
107
|
-
|
|
108
|
-
@injectable()
|
|
109
|
-
export class FeedbackActionDispatcher implements IFeedbackActionDispatcher {
|
|
110
|
-
protected registeredFeedback: Map<IFeedbackEmitter, Action[]> = new Map();
|
|
111
|
-
|
|
112
|
-
@inject(TYPES.IActionDispatcherProvider) protected actionDispatcher: () => Promise<IActionDispatcher>;
|
|
113
|
-
@inject(TYPES.ILogger) protected logger: ILogger;
|
|
114
|
-
|
|
115
|
-
@inject(ActionHandlerRegistry) protected actionHandlerRegistry: ActionHandlerRegistry;
|
|
116
|
-
|
|
117
|
-
registerFeedback(feedbackEmitter: IFeedbackEmitter, feedbackActions: Action[], cleanupActions?: MaybeActions): Disposable {
|
|
118
|
-
if (feedbackEmitter instanceof GModelElement) {
|
|
119
|
-
this.logger.log(
|
|
120
|
-
this,
|
|
121
|
-
// eslint-disable-next-line max-len
|
|
122
|
-
'GModelElements as feedback emitters are discouraged, as they usually change between model updates and are considered unstable.'
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
if (feedbackActions.length > 0) {
|
|
126
|
-
this.registeredFeedback.set(feedbackEmitter, feedbackActions);
|
|
127
|
-
this.dispatchFeedback(feedbackActions, feedbackEmitter);
|
|
128
|
-
}
|
|
129
|
-
return Disposable.create(() => this.deregisterFeedback(feedbackEmitter, cleanupActions));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
deregisterFeedback(feedbackEmitter: IFeedbackEmitter, cleanupActions?: MaybeActions): void {
|
|
133
|
-
this.registeredFeedback.delete(feedbackEmitter);
|
|
134
|
-
const actions = MaybeActions.asArray(cleanupActions);
|
|
135
|
-
if (actions.length > 0) {
|
|
136
|
-
this.dispatchFeedback(actions, feedbackEmitter);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
getRegisteredFeedback(): Action[] {
|
|
141
|
-
const result: Action[] = [];
|
|
142
|
-
this.registeredFeedback.forEach(actions => result.push(...actions));
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
getRegisteredFeedbackEmitters(action: Action): IFeedbackEmitter[] {
|
|
147
|
-
const result: IFeedbackEmitter[] = [];
|
|
148
|
-
this.registeredFeedback.forEach((actions, emitter) => {
|
|
149
|
-
if (actions.includes(action)) {
|
|
150
|
-
result.push(emitter);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
getFeedbackCommands(): Command[] {
|
|
157
|
-
return this.getRegisteredFeedback()
|
|
158
|
-
.flatMap(action => this.actionToCommands(action))
|
|
159
|
-
.sort((left, right) => getFeedbackRank(left) - getFeedbackRank(right));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async applyFeedbackCommands(context: CommandExecutionContext): Promise<void> {
|
|
163
|
-
const feedbackCommands = this.getFeedbackCommands() ?? [];
|
|
164
|
-
if (feedbackCommands?.length > 0) {
|
|
165
|
-
const results = feedbackCommands.map(command => command.execute(context));
|
|
166
|
-
await Promise.all(results);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
protected actionToCommands(action: Action): ICommand[] {
|
|
171
|
-
return (
|
|
172
|
-
this.actionHandlerRegistry
|
|
173
|
-
.get(action.kind)
|
|
174
|
-
.filter(toTypeGuard(CommandActionHandler))
|
|
175
|
-
.map(handler => handler.handle(action)) ?? []
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
createEmitter(): FeedbackEmitter {
|
|
180
|
-
return new FeedbackEmitter(this);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
protected async dispatchFeedback(actions: Action[], feedbackEmitter: IFeedbackEmitter): Promise<void> {
|
|
184
|
-
try {
|
|
185
|
-
const actionDispatcher = await this.actionDispatcher();
|
|
186
|
-
await actionDispatcher.dispatchAll(actions);
|
|
187
|
-
this.logger.info(this, `Dispatched feedback actions for ${feedbackEmitter}`);
|
|
188
|
-
} catch (reason) {
|
|
189
|
-
this.logger.error(this, 'Failed to dispatch feedback actions', reason);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -0,0 +1,176 @@
|
|
|
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 { Action, Command, CommandExecutionContext, Disposable } from '@eclipse-glsp/sprotty';
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { IFeedbackActionDispatcher, IFeedbackEmitter } from './feedback-action-dispatcher';
|
|
19
|
+
import { FeedbackEmitter } from './feedback-emitter';
|
|
20
|
+
|
|
21
|
+
class MockFeedbackActionDispatcher implements IFeedbackActionDispatcher {
|
|
22
|
+
protected feedbackEmitters: Map<IFeedbackEmitter, Action[]> = new Map();
|
|
23
|
+
|
|
24
|
+
registerFeedback(feedbackEmitter: IFeedbackEmitter, actions: Action[]): Disposable {
|
|
25
|
+
this.feedbackEmitters.set(feedbackEmitter, actions);
|
|
26
|
+
return Disposable.create(() => this.deregisterFeedback(feedbackEmitter));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
deregisterFeedback(feedbackEmitter: IFeedbackEmitter, _actions?: Action[]): void {
|
|
30
|
+
this.feedbackEmitters.delete(feedbackEmitter);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getRegisteredFeedback(): Action[] {
|
|
34
|
+
const result: Action[] = [];
|
|
35
|
+
this.feedbackEmitters.forEach((value, key) => result.push(...value));
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getFeedbackCommands(): Command[] {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
createEmitter(): FeedbackEmitter {
|
|
44
|
+
return new FeedbackEmitter(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async applyFeedbackCommands(context: CommandExecutionContext): Promise<void> {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe('FeedbackEmitter', () => {
|
|
51
|
+
describe('Initial State', () => {
|
|
52
|
+
it('On creation nothing should be submitted.', () => {
|
|
53
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
54
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
55
|
+
feedback.submit();
|
|
56
|
+
expect(feedbackActionDispatcher['feedbackEmitters']).to.be.empty;
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('Adding Feedback', () => {
|
|
61
|
+
it('Should add an action as part of the emitter feedback.', () => {
|
|
62
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
63
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
64
|
+
const action: Action = { kind: 'action' };
|
|
65
|
+
feedback.add(action);
|
|
66
|
+
expect(feedback['feedbackActions']).to.deep.equal([action]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('Should add an action and cleanup action as part of the emitter feedback.', () => {
|
|
70
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
71
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
72
|
+
const action: Action = { kind: 'action' };
|
|
73
|
+
const cleanupAction: Action = { kind: 'cleanup' };
|
|
74
|
+
feedback.add(action, cleanupAction);
|
|
75
|
+
expect(feedback['feedbackActions']).to.deep.equal([action]);
|
|
76
|
+
expect(feedback['cleanupActions']).to.deep.equal([cleanupAction]);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('Merging Feedback', () => {
|
|
81
|
+
it('Should merge the feedback of another emitter into this emitter.', () => {
|
|
82
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
83
|
+
const feedback1 = feedbackActionDispatcher.createEmitter();
|
|
84
|
+
const feedback2 = feedbackActionDispatcher.createEmitter();
|
|
85
|
+
const action1: Action = { kind: 'action1' };
|
|
86
|
+
const action2: Action = { kind: 'action2' };
|
|
87
|
+
feedback1.add(action1);
|
|
88
|
+
feedback2.add(action2);
|
|
89
|
+
feedback1.merge(feedback2);
|
|
90
|
+
expect(feedback1['feedbackActions']).to.deep.equal([action1, action2]);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('Removing Feedback', () => {
|
|
95
|
+
it('Should remove the action from the emitter feedback.', () => {
|
|
96
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
97
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
98
|
+
const action: Action = { kind: 'action' };
|
|
99
|
+
feedback.add(action);
|
|
100
|
+
feedback.remove(action);
|
|
101
|
+
expect(feedback['feedbackActions']).to.be.empty;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('Should remove the action together with the cleanup action from the emitter feedback.', () => {
|
|
105
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
106
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
107
|
+
const action: Action = { kind: 'action' };
|
|
108
|
+
const cleanupAction: Action = { kind: 'cleanup' };
|
|
109
|
+
feedback.add(action, cleanupAction);
|
|
110
|
+
feedback.remove(action);
|
|
111
|
+
expect(feedback['feedbackActions']).to.be.empty;
|
|
112
|
+
expect(feedback['cleanupActions']).to.be.empty;
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('Clearing Feedback', () => {
|
|
117
|
+
it('Should clear any pending feedback actions and cleanup actions.', () => {
|
|
118
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
119
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
120
|
+
const action: Action = { kind: 'action' };
|
|
121
|
+
const cleanupAction: Action = { kind: 'cleanup' };
|
|
122
|
+
feedback.add(action, cleanupAction);
|
|
123
|
+
feedback.clear();
|
|
124
|
+
expect(feedback['feedbackActions']).to.be.empty;
|
|
125
|
+
expect(feedback['cleanupActions']).to.be.empty;
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('Submitting Feedback', () => {
|
|
130
|
+
it('Should register any pending actions as feedback.', () => {
|
|
131
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
132
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
133
|
+
const action: Action = { kind: 'action' };
|
|
134
|
+
feedback.add(action);
|
|
135
|
+
feedback.submit();
|
|
136
|
+
expect(feedbackActionDispatcher['feedbackEmitters'].size).to.equal(1);
|
|
137
|
+
expect(feedbackActionDispatcher['feedbackEmitters'].get(feedback)).to.deep.equal([action]);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Discarding Feedback', () => {
|
|
142
|
+
it('Should remove the registered feedback without calling any cleanup actions.', () => {
|
|
143
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
144
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
145
|
+
const action: Action = { kind: 'action' };
|
|
146
|
+
feedback.add(action);
|
|
147
|
+
feedback.submit();
|
|
148
|
+
feedback.discard();
|
|
149
|
+
expect(feedbackActionDispatcher['feedbackEmitters']).to.be.empty;
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('Reverting Feedback', () => {
|
|
154
|
+
it('Should remove the registered feedback and call the registered cleanup actions.', () => {
|
|
155
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
156
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
157
|
+
const action: Action = { kind: 'action' };
|
|
158
|
+
const cleanupAction: Action = { kind: 'cleanup' };
|
|
159
|
+
feedback.add(action, cleanupAction);
|
|
160
|
+
feedback.submit();
|
|
161
|
+
feedback.revert();
|
|
162
|
+
expect(feedbackActionDispatcher['feedbackEmitters']).to.be.empty;
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Disposing Feedback', () => {
|
|
167
|
+
it('Should dispose the registered feedback and any pending feedback actions.', () => {
|
|
168
|
+
const feedbackActionDispatcher = new MockFeedbackActionDispatcher();
|
|
169
|
+
const feedback = feedbackActionDispatcher.createEmitter();
|
|
170
|
+
const action: Action = { kind: 'action' };
|
|
171
|
+
feedback.add(action);
|
|
172
|
+
feedback.dispose();
|
|
173
|
+
expect(feedbackActionDispatcher['feedbackEmitters']).to.be.empty;
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -17,10 +17,14 @@
|
|
|
17
17
|
import { Action, Disposable, arrayOf } from '@eclipse-glsp/sprotty';
|
|
18
18
|
import { IFeedbackActionDispatcher, IFeedbackEmitter, MaybeActions } from './feedback-action-dispatcher';
|
|
19
19
|
|
|
20
|
+
// counter for internal id, mainly useful for debugging
|
|
21
|
+
let idCounter = 0;
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* A helper object to collect, submit and undo feedback consisting of several actions.
|
|
22
25
|
*/
|
|
23
26
|
export class FeedbackEmitter implements IFeedbackEmitter, Disposable {
|
|
27
|
+
protected id = idCounter++;
|
|
24
28
|
protected feedbackActions: (Action | undefined)[] = [];
|
|
25
29
|
protected cleanupActions: MaybeActions[] = [];
|
|
26
30
|
protected deregistration?: Disposable;
|
|
@@ -46,6 +50,17 @@ export class FeedbackEmitter implements IFeedbackEmitter, Disposable {
|
|
|
46
50
|
return this;
|
|
47
51
|
}
|
|
48
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Merges the feedback of another emitter into this emitter.
|
|
55
|
+
*
|
|
56
|
+
* @param feedback feedback to merge
|
|
57
|
+
*/
|
|
58
|
+
merge(feedback: FeedbackEmitter): this {
|
|
59
|
+
this.feedbackActions.push(...feedback.feedbackActions);
|
|
60
|
+
this.cleanupActions.push(...feedback.cleanupActions);
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
/**
|
|
50
65
|
* Removes the action as part of this emitters feedback. If the action cannot be found, this is a no-op.
|
|
51
66
|
* Please note that this also removed the corresponding cleanup action.
|
|
@@ -56,9 +71,9 @@ export class FeedbackEmitter implements IFeedbackEmitter, Disposable {
|
|
|
56
71
|
*/
|
|
57
72
|
remove(action: Action): this {
|
|
58
73
|
const idx = this.feedbackActions.indexOf(action);
|
|
59
|
-
if (idx) {
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
if (idx >= 0) {
|
|
75
|
+
this.feedbackActions.splice(idx, 1);
|
|
76
|
+
this.cleanupActions.splice(idx, 1);
|
|
62
77
|
}
|
|
63
78
|
return this;
|
|
64
79
|
}
|
|
@@ -79,8 +94,12 @@ export class FeedbackEmitter implements IFeedbackEmitter, Disposable {
|
|
|
79
94
|
// with 'arrayOf' we skip undefined entries that are created for non-cleanup actions or cleanup-only actions
|
|
80
95
|
const actions = arrayOf(...this.feedbackActions);
|
|
81
96
|
const cleanupActions = arrayOf(...this.cleanupActions);
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
if (actions.length > 0 || cleanupActions.length > 0) {
|
|
98
|
+
this.deregistration = this.feedbackDispatcher.registerFeedback(this, actions, () =>
|
|
99
|
+
cleanupActions.flatMap(MaybeActions.asArray)
|
|
100
|
+
);
|
|
101
|
+
this.clear();
|
|
102
|
+
}
|
|
84
103
|
return this;
|
|
85
104
|
}
|
|
86
105
|
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
export * from './css-feedback';
|
|
17
|
-
export * from './feeback-emitter';
|
|
18
17
|
export * from './feedback-action-dispatcher';
|
|
18
|
+
export * from './feedback-action-dispatcher-default';
|
|
19
19
|
export * from './feedback-command';
|
|
20
|
+
export * from './feedback-emitter';
|
|
20
21
|
export * from './set-model-command';
|
|
21
22
|
export * from './update-model-command';
|
|
@@ -18,8 +18,8 @@ import { AssertionError, expect } from 'chai';
|
|
|
18
18
|
import { Container, injectable } from 'inversify';
|
|
19
19
|
import * as sinon from 'sinon';
|
|
20
20
|
import { defaultModule } from './default.module';
|
|
21
|
-
import { FeedbackEmitter } from './feedback/feeback-emitter';
|
|
22
21
|
import { IFeedbackActionDispatcher, IFeedbackEmitter } from './feedback/feedback-action-dispatcher';
|
|
22
|
+
import { FeedbackEmitter } from './feedback/feedback-emitter';
|
|
23
23
|
import { ISelectionListener, SelectFeedbackAction, SelectionService } from './selection-service';
|
|
24
24
|
|
|
25
25
|
@injectable()
|
|
@@ -41,7 +41,7 @@ export class MovementKeyTool implements Tool {
|
|
|
41
41
|
@inject(TYPES.ISnapper) @optional() readonly snapper?: ISnapper;
|
|
42
42
|
@inject(TYPES.IActionDispatcher) readonly actionDispatcher: GLSPActionDispatcher;
|
|
43
43
|
@inject(TYPES.Grid) @optional() protected grid: Grid;
|
|
44
|
-
@inject(
|
|
44
|
+
@inject(ChangeBoundsManager) readonly changeBoundsManager: ChangeBoundsManager;
|
|
45
45
|
|
|
46
46
|
get id(): string {
|
|
47
47
|
return MovementKeyTool.ID;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import {
|
|
17
17
|
Bounds,
|
|
18
|
+
Direction,
|
|
18
19
|
GChildElement,
|
|
19
20
|
GModelElement,
|
|
20
21
|
GParentElement,
|
|
@@ -47,6 +48,20 @@ export enum ResizeHandleLocation {
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
export namespace ResizeHandleLocation {
|
|
51
|
+
export const CORNERS: ResizeHandleLocation[] = [
|
|
52
|
+
ResizeHandleLocation.TopLeft,
|
|
53
|
+
ResizeHandleLocation.TopRight,
|
|
54
|
+
ResizeHandleLocation.BottomRight,
|
|
55
|
+
ResizeHandleLocation.BottomLeft
|
|
56
|
+
];
|
|
57
|
+
export const CROSS: ResizeHandleLocation[] = [
|
|
58
|
+
ResizeHandleLocation.Top,
|
|
59
|
+
ResizeHandleLocation.Right,
|
|
60
|
+
ResizeHandleLocation.Bottom,
|
|
61
|
+
ResizeHandleLocation.Left
|
|
62
|
+
];
|
|
63
|
+
export const ALL = Object.values(ResizeHandleLocation).filter(value => typeof value !== 'function') as ResizeHandleLocation[];
|
|
64
|
+
|
|
50
65
|
export function opposite(location: ResizeHandleLocation): ResizeHandleLocation {
|
|
51
66
|
switch (location) {
|
|
52
67
|
case ResizeHandleLocation.TopLeft:
|
|
@@ -67,6 +82,27 @@ export namespace ResizeHandleLocation {
|
|
|
67
82
|
return ResizeHandleLocation.Right;
|
|
68
83
|
}
|
|
69
84
|
}
|
|
85
|
+
|
|
86
|
+
export function direction(location: ResizeHandleLocation): Direction[] {
|
|
87
|
+
switch (location) {
|
|
88
|
+
case ResizeHandleLocation.TopLeft:
|
|
89
|
+
return [Direction.Up, Direction.Left];
|
|
90
|
+
case ResizeHandleLocation.Top:
|
|
91
|
+
return [Direction.Up];
|
|
92
|
+
case ResizeHandleLocation.TopRight:
|
|
93
|
+
return [Direction.Up, Direction.Right];
|
|
94
|
+
case ResizeHandleLocation.Right:
|
|
95
|
+
return [Direction.Right];
|
|
96
|
+
case ResizeHandleLocation.BottomRight:
|
|
97
|
+
return [Direction.Down, Direction.Right];
|
|
98
|
+
case ResizeHandleLocation.Bottom:
|
|
99
|
+
return [Direction.Down];
|
|
100
|
+
case ResizeHandleLocation.BottomLeft:
|
|
101
|
+
return [Direction.Down, Direction.Left];
|
|
102
|
+
case ResizeHandleLocation.Left:
|
|
103
|
+
return [Direction.Left];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
70
106
|
}
|
|
71
107
|
|
|
72
108
|
export function isBoundsAwareMoveable(element: GModelElement): element is BoundsAwareModelElement & MoveableElement {
|
|
@@ -182,19 +218,8 @@ export class SResizeHandle extends GChildElement implements Hoverable {
|
|
|
182
218
|
}
|
|
183
219
|
}
|
|
184
220
|
|
|
185
|
-
export function addResizeHandles(
|
|
186
|
-
|
|
187
|
-
locations: ResizeHandleLocation[] = [
|
|
188
|
-
ResizeHandleLocation.TopLeft,
|
|
189
|
-
ResizeHandleLocation.Top,
|
|
190
|
-
ResizeHandleLocation.BottomLeft,
|
|
191
|
-
ResizeHandleLocation.BottomRight
|
|
192
|
-
]
|
|
193
|
-
): void {
|
|
194
|
-
for (const location of Object.values(ResizeHandleLocation)) {
|
|
195
|
-
if (typeof location === 'function') {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
221
|
+
export function addResizeHandles(element: ResizableModelElement, locations: ResizeHandleLocation[] = ResizeHandleLocation.CORNERS): void {
|
|
222
|
+
for (const location of ResizeHandleLocation.ALL) {
|
|
198
223
|
const existing = element.children.find(child => child instanceof SResizeHandle && child.location === location);
|
|
199
224
|
if (locations.includes(location) && !existing) {
|
|
200
225
|
// add missing handle
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Bounds, GModelElement, GNode, GParentElement, Point } from '@eclipse-glsp/sprotty';
|
|
16
|
+
import { Bounds, Dimension, GModelElement, GNode, GParentElement, Point, isBoundsAware, isMoveable } from '@eclipse-glsp/sprotty';
|
|
17
17
|
import { injectable } from 'inversify';
|
|
18
18
|
import { ModifyCSSFeedbackAction } from '../../base/feedback/css-feedback';
|
|
19
19
|
import { BoundsAwareModelElement } from '../../utils';
|
|
20
20
|
import { toAbsoluteBounds } from '../../utils/viewpoint-util';
|
|
21
|
-
import { SResizeHandle
|
|
21
|
+
import { SResizeHandle } from './model';
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* A `MovementRestrictor` is an optional service that can be used by tools to validate
|
|
@@ -48,27 +48,27 @@ export class NoOverlapMovementRestrictor implements IMovementRestrictor {
|
|
|
48
48
|
cssClasses = ['movement-not-allowed'];
|
|
49
49
|
|
|
50
50
|
validate(element: GModelElement, newLocation?: Point): boolean {
|
|
51
|
-
if (!
|
|
51
|
+
if (!isMoveable(element) || !newLocation) {
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
54
|
// Create ghost element at the newLocation
|
|
55
|
+
const dimensions: Dimension = isBoundsAware(element) ? element.bounds : { width: 1, height: 1 };
|
|
55
56
|
const ghostElement = Object.create(element) as BoundsAwareModelElement;
|
|
56
|
-
ghostElement.bounds = {
|
|
57
|
-
x: newLocation.x,
|
|
58
|
-
y: newLocation.y,
|
|
59
|
-
width: element.bounds.width,
|
|
60
|
-
height: element.bounds.height
|
|
61
|
-
};
|
|
57
|
+
ghostElement.bounds = { ...dimensions, ...newLocation };
|
|
62
58
|
ghostElement.type = 'Ghost';
|
|
63
59
|
ghostElement.id = element.id;
|
|
64
60
|
return !Array.from(
|
|
65
61
|
element.root.index
|
|
66
62
|
.all()
|
|
67
|
-
.filter(
|
|
68
|
-
.map(
|
|
63
|
+
.filter(node => node.id !== ghostElement.id && node !== ghostElement.root && node instanceof GNode)
|
|
64
|
+
.map(node => node as BoundsAwareModelElement)
|
|
69
65
|
).some(e => this.areOverlapping(e, ghostElement));
|
|
70
66
|
}
|
|
71
67
|
|
|
68
|
+
protected isBoundsRelevant(element: GModelElement, ghostElement: BoundsAwareModelElement): element is BoundsAwareModelElement {
|
|
69
|
+
return element.id !== ghostElement.id && element !== ghostElement.root && element instanceof GNode && isBoundsAware(element);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
72
|
protected areOverlapping(element1: BoundsAwareModelElement, element2: BoundsAwareModelElement): boolean {
|
|
73
73
|
return Bounds.overlap(toAbsoluteBounds(element1), toAbsoluteBounds(element2));
|
|
74
74
|
}
|
|
@@ -35,15 +35,12 @@ export class CopyPasteStartup implements IDiagramStartup, Disposable {
|
|
|
35
35
|
}
|
|
36
36
|
const copyListener = (e: ClipboardEvent): void => {
|
|
37
37
|
this.copyPasteHandler?.handleCopy(e);
|
|
38
|
-
e.preventDefault();
|
|
39
38
|
};
|
|
40
39
|
const cutListener = (e: ClipboardEvent): void => {
|
|
41
40
|
this.copyPasteHandler?.handleCut(e);
|
|
42
|
-
e.preventDefault();
|
|
43
41
|
};
|
|
44
42
|
const pasteListener = (e: ClipboardEvent): void => {
|
|
45
43
|
this.copyPasteHandler?.handlePaste(e);
|
|
46
|
-
e.preventDefault();
|
|
47
44
|
};
|
|
48
45
|
window.addEventListener('copy', copyListener);
|
|
49
46
|
window.addEventListener('cut', cutListener);
|