Skip to content

Commit 8c40df4

Browse files
authored
GLSP-1588: Fix decoration SVG export (#451)
- Readd missing check to only dispatch a hidden bounds update if caused by RequestBoundsAction - Fix decoration placement in exported SVG eclipse-glsp/glsp#1588
1 parent 4f29c67 commit 8c40df4

File tree

4 files changed

+58
-7
lines changed

4 files changed

+58
-7
lines changed

packages/client/src/features/bounds/glsp-hidden-bounds-updater.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2022-2024 EclipseSource and others.
2+
* Copyright (c) 2022-2025 EclipseSource and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -65,6 +65,10 @@ export class GLSPHiddenBoundsUpdater extends HiddenBoundsUpdater {
6565
}
6666

6767
override postUpdate(cause?: Action): void {
68+
if (cause === undefined || cause.kind !== RequestBoundsAction.KIND) {
69+
return;
70+
}
71+
6872
if (LocalRequestBoundsAction.is(cause) && cause.elementIDs) {
6973
this.focusOnElements(cause.elementIDs);
7074
}

packages/client/src/features/decoration/decoration-module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2019-2024 EclipseSource and others.
2+
* Copyright (c) 2019-2025 EclipseSource and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -20,6 +20,7 @@ import { GlspDecorationPlacer } from './decoration-placer';
2020
export const decorationModule = new FeatureModule(
2121
bind => {
2222
bindAsService(bind, TYPES.IVNodePostprocessor, GlspDecorationPlacer);
23+
bind(TYPES.ISvgExportPostprocessor).toService(GlspDecorationPlacer);
2324
},
2425
{ featureId: Symbol('decoration') }
2526
);

packages/client/src/features/decoration/decoration-placer.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2019-2023 EclipseSource and others.
2+
* Copyright (c) 2019-2025 EclipseSource and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,12 +13,37 @@
1313
*
1414
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515
********************************************************************************/
16-
import { Decoration, DecorationPlacer, GChildElement, GModelElement, GRoutableElement, Point, isSizeable } from '@eclipse-glsp/sprotty';
17-
import { injectable } from 'inversify';
16+
import {
17+
Action,
18+
DOMHelper,
19+
Decoration,
20+
DecorationPlacer,
21+
GChildElement,
22+
GModelElement,
23+
GRoutableElement,
24+
ISvgExportPostProcessor,
25+
LazyInjector,
26+
Point,
27+
TYPES,
28+
isDecoration,
29+
isSizeable
30+
} from '@eclipse-glsp/sprotty';
31+
import { inject, injectable } from 'inversify';
32+
import { EditorContextService } from '../../base/editor-context-service';
33+
import { filter } from '../../utils/gmodel-util';
1834

1935
@injectable()
20-
export class GlspDecorationPlacer extends DecorationPlacer {
36+
export class GlspDecorationPlacer extends DecorationPlacer implements ISvgExportPostProcessor {
2137
protected static readonly DECORATION_OFFSET: Point = { x: 12, y: 10 };
38+
@inject(TYPES.DOMHelper)
39+
protected domHelper: DOMHelper;
40+
41+
@inject(LazyInjector)
42+
protected lazyInjector: LazyInjector;
43+
44+
get editorContextService(): EditorContextService {
45+
return this.lazyInjector.get(EditorContextService);
46+
}
2247

2348
protected override getPosition(element: GModelElement & Decoration): Point {
2449
if (element instanceof GChildElement && element.parent instanceof GRoutableElement) {
@@ -32,4 +57,24 @@ export class GlspDecorationPlacer extends DecorationPlacer {
3257
}
3358
return Point.ORIGIN;
3459
}
60+
// HiddenVNodePostprocessor implementation
61+
override postUpdate(cause?: Action): void;
62+
// ISvgExportPostProcessor implementation
63+
override postUpdate(element: SVGSVGElement, cause?: Action): void;
64+
override postUpdate(elementOrCause?: SVGSVGElement | Action, _cause?: Action): void {
65+
// Called as HiddenVNodePostprocessor => no-op
66+
if (!elementOrCause || Action.is(elementOrCause)) {
67+
return;
68+
}
69+
70+
// Called as ISvgExportPostProcessor
71+
// Adjust the position of all decorations in the exported SVG
72+
const svg = elementOrCause;
73+
const translate = `translate(-${GlspDecorationPlacer.DECORATION_OFFSET.x}px, -${GlspDecorationPlacer.DECORATION_OFFSET.y}px)`;
74+
filter(this.editorContextService.modelRoot.index, isDecoration).forEach(decoration => {
75+
const domId = this.domHelper.createUniqueDOMElementId(decoration);
76+
const element = svg.querySelector<SVGElement>(`#${domId}`);
77+
element!.style.transform = translate;
78+
});
79+
}
3580
}

packages/glsp-sprotty/src/re-exports.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export * from 'sprotty/lib/features/bounds/views';
127127
export { ButtonHandlerRegistry, configureButtonHandler, IButtonHandlerRegistration } from 'sprotty/lib/features/button/button-handler';
128128
export { SButtonImpl as GButton } from 'sprotty/lib/features/button/model';
129129

130-
// exlucde ICommandPaletteActionProvider. Exported via api-override module instead
130+
// exclude ICommandPaletteActionProvider. Exported via api-override module instead
131131
export {
132132
CommandPaletteActionProviderRegistry,
133133
RevealNamedElementActionProvider
@@ -159,6 +159,7 @@ export * from 'sprotty/lib/features/expand/views';
159159
export { ExportSvgCommand, ExportSvgKeyListener, ExportSvgPostprocessor } from 'sprotty/lib/features/export/export';
160160
export * from 'sprotty/lib/features/export/model';
161161
// Exclude ExportSvgAction. Already provided by glsp-protocol
162+
export * from 'sprotty/lib/features/export/svg-export-postprocessor';
162163
export { SvgExporter } from 'sprotty/lib/features/export/svg-exporter';
163164

164165
export * from 'sprotty/lib/features/fade/fade';

0 commit comments

Comments
 (0)