@geogirafe/lib-geoportal 1.0.2250856094 → 1.0.2259547422
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/api/apigeogirafeapp.js +1 -1
- package/components/basemap/component.js +3 -4
- package/components/map/component.js +6 -0
- package/models/basemaps/basemap.d.ts +1 -0
- package/models/basemaps/basemap.js +3 -0
- package/package.json +1 -1
- package/templates/public/about.json +1 -1
- package/tools/configuration/girafeconfig.d.ts +1 -0
- package/tools/configuration/girafeconfig.js +2 -1
- package/tools/error/errormanager.js +1 -1
- package/tools/main.d.ts +1 -1
- package/tools/share/serializers/activebasemapsserializer.d.ts +4 -1
- package/tools/share/serializers/activebasemapsserializer.js +33 -23
- package/tools/share/serializers/activebasemapsserializer.spec.js +86 -4
- package/tools/share/serializers/layerconfigserializer.d.ts +6 -1
- package/tools/share/serializers/layerconfigserializer.js +95 -13
- package/tools/share/serializers/layerconfigserializer.spec.js +75 -3
- package/tools/share/serializers/sharedtypes.d.ts +20 -0
package/api/apigeogirafeapp.js
CHANGED
|
@@ -115,7 +115,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
|
|
|
115
115
|
}
|
|
116
116
|
injectConfigMetaTags() {
|
|
117
117
|
const location = new URL(import.meta.url);
|
|
118
|
-
if (import.meta
|
|
118
|
+
if (import.meta?.env?.DEV) {
|
|
119
119
|
location.pathname = location.pathname.replace('/src/api', '');
|
|
120
120
|
}
|
|
121
121
|
const origin = `${location.origin}${location.pathname.substring(0, location.pathname.lastIndexOf('/'))}`;
|
|
@@ -18,12 +18,11 @@ class BasemapComponent extends GirafeHTMLElement {
|
|
|
18
18
|
if (basemap.opacity == 0)
|
|
19
19
|
return;
|
|
20
20
|
const newBasemapProjection = basemap.projection ?? this.context.configManager.Config.map.srid;
|
|
21
|
-
const opacityDisabled = basemap.opacity == -1;
|
|
22
21
|
const activeBasemaps = [...this.state.activeBasemaps];
|
|
23
|
-
if (opacityDisabled) {
|
|
22
|
+
if (basemap.opacityDisabled) {
|
|
24
23
|
// Normal basemap change (no opacity basemap)
|
|
25
24
|
this.state.projection = newBasemapProjection;
|
|
26
|
-
const idx = activeBasemaps.findIndex((activeBasemap) => activeBasemap.
|
|
25
|
+
const idx = activeBasemaps.findIndex((activeBasemap) => activeBasemap.opacityDisabled);
|
|
27
26
|
if (idx >= 0) {
|
|
28
27
|
activeBasemaps.splice(idx, 1);
|
|
29
28
|
}
|
|
@@ -51,7 +50,7 @@ class BasemapComponent extends GirafeHTMLElement {
|
|
|
51
50
|
}
|
|
52
51
|
changeBasemapOpacity(basemap, e) {
|
|
53
52
|
e.stopPropagation();
|
|
54
|
-
if (basemap.
|
|
53
|
+
if (basemap.opacityDisabled) {
|
|
55
54
|
console.warn(`Trying to set Opacity on Basemap '${basemap.name}' which does not allow it`);
|
|
56
55
|
return;
|
|
57
56
|
}
|
|
@@ -885,6 +885,12 @@ export default class MapComponent extends GirafeHTMLElement {
|
|
|
885
885
|
throw new TypeError('Unknown basemap type');
|
|
886
886
|
}
|
|
887
887
|
}
|
|
888
|
+
// Apply default opacity
|
|
889
|
+
for (const basemap of basemaps) {
|
|
890
|
+
if (!basemap.opacityDisabled) {
|
|
891
|
+
this.onChangeBasemapOpacity(basemap);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
888
894
|
}
|
|
889
895
|
/**
|
|
890
896
|
* This method checks for the presence of an initial selection originating from a shared state.
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.0.
|
|
1
|
+
{"version":"1.0.2259547422", "build":"2259547422", "date":"13/01/2026"}
|
|
@@ -162,6 +162,7 @@ class GirafeConfig {
|
|
|
162
162
|
}
|
|
163
163
|
return {
|
|
164
164
|
service: config.share?.service ?? 'gmf',
|
|
165
|
+
preferNames: config.share?.preferNames ?? false,
|
|
165
166
|
createUrl: config.share?.createUrl,
|
|
166
167
|
getUrl: config.share?.getUrl
|
|
167
168
|
};
|
|
@@ -300,7 +301,7 @@ class GirafeConfig {
|
|
|
300
301
|
locale: config.general.locale ?? GirafeConfig.DEFAULT_LOCALE,
|
|
301
302
|
// NOTE REG: Small hack specific to Vite: When running in debug mode, we force the logLevel to debug.
|
|
302
303
|
// Otherwise we will always have to manually activate it.
|
|
303
|
-
logLevel: import.meta
|
|
304
|
+
logLevel: import.meta?.env?.DEV ? 'debug' : (config.general.logLevel ?? 'warn')
|
|
304
305
|
};
|
|
305
306
|
}
|
|
306
307
|
initGmfOauth(config) {
|
|
@@ -61,7 +61,7 @@ ${stack}
|
|
|
61
61
|
if (error?.stack) {
|
|
62
62
|
try {
|
|
63
63
|
// NOTE REG: Specific to Vite: When running in debug mode, we do not need to calculate the original stacktrace
|
|
64
|
-
stack = import.meta
|
|
64
|
+
stack = import.meta?.env?.DEV ? error.stack : await this.getOriginalStackTrace(error);
|
|
65
65
|
}
|
|
66
66
|
catch (e) {
|
|
67
67
|
// If an error accurs during the calculation of the stacktrace, we just ignore it
|
package/tools/main.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export { default as LayersConfigSerializer } from './share/serializers/layerconf
|
|
|
54
54
|
export { default as MapPositionSerializer } from './share/serializers/mappositionserializer.js';
|
|
55
55
|
export type { SharedInitialSelection } from './share/serializers/selectionserializer.js';
|
|
56
56
|
export { default as SelectionSerializer } from './share/serializers/selectionserializer.js';
|
|
57
|
-
export type { SharedFilter, SharedLayer, SharedInternalTheme, SharedInternalGroup, SharedInternalLayer, SharedExternalTheme, SharedExternalLayer } from './share/serializers/sharedtypes.js';
|
|
57
|
+
export type { SharedFilter, SharedLayer, SharedInternalTheme, SharedInternalGroup, SharedInternalLayer, SharedExternalTheme, SharedExternalLayer, SharedBasemap } from './share/serializers/sharedtypes.js';
|
|
58
58
|
export { default as SessionManager } from './share/sessionmanager.js';
|
|
59
59
|
export { default as ShareManager } from './share/sharemanager.js';
|
|
60
60
|
export { default as StateSerializer } from './share/stateserializer.js';
|
|
@@ -5,6 +5,9 @@ export default class ActiveBasemapsSerializer implements IBrainSerializer<Basema
|
|
|
5
5
|
private readonly context;
|
|
6
6
|
constructor(context: IGirafeContext);
|
|
7
7
|
private get state();
|
|
8
|
-
|
|
8
|
+
private get preferNames();
|
|
9
|
+
brainSerialize(activeBasemaps: Basemap[]): string;
|
|
9
10
|
brainDeserialize(serializedString: string): void;
|
|
11
|
+
private serialize;
|
|
12
|
+
private deserialize;
|
|
10
13
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { applyOpacityToLayers } from '../../utils/utils.js';
|
|
2
|
-
import { DEFAULT_OPACITY } from '../../themes/themes-config.js';
|
|
3
1
|
export default class ActiveBasemapsSerializer {
|
|
4
2
|
context;
|
|
5
3
|
constructor(context) {
|
|
@@ -8,31 +6,43 @@ export default class ActiveBasemapsSerializer {
|
|
|
8
6
|
get state() {
|
|
9
7
|
return this.context.stateManager.state;
|
|
10
8
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return serializedBasemaps;
|
|
9
|
+
get preferNames() {
|
|
10
|
+
return this.context.configManager.Config.share?.preferNames ?? false;
|
|
11
|
+
}
|
|
12
|
+
brainSerialize(activeBasemaps) {
|
|
13
|
+
return this.serialize(activeBasemaps);
|
|
17
14
|
}
|
|
18
15
|
brainDeserialize(serializedString) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const activeBasemaps = this.deserialize(serializedString);
|
|
17
|
+
this.state.activeBasemaps = activeBasemaps;
|
|
18
|
+
}
|
|
19
|
+
serialize(basemaps) {
|
|
20
|
+
const sharedBasemaps = [];
|
|
23
21
|
for (const basemap of basemaps) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const sharedBasemap = {
|
|
23
|
+
id: basemap.id,
|
|
24
|
+
name: basemap.name,
|
|
25
|
+
opacity: basemap.opacity
|
|
26
|
+
};
|
|
27
|
+
sharedBasemaps.push(sharedBasemap);
|
|
29
28
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
return JSON.stringify(sharedBasemaps);
|
|
30
|
+
}
|
|
31
|
+
deserialize(str) {
|
|
32
|
+
const sharedBasemaps = JSON.parse(str);
|
|
33
|
+
const basemaps = [];
|
|
34
|
+
for (const sharedBasemap of sharedBasemaps) {
|
|
35
|
+
const basemap = this.preferNames
|
|
36
|
+
? Object.values(this.state.basemaps).find((b) => b.name === sharedBasemap.name)
|
|
37
|
+
: Object.values(this.state.basemaps).find((b) => b.id === sharedBasemap.id);
|
|
38
|
+
if (basemap) {
|
|
39
|
+
basemap.opacity = sharedBasemap.opacity;
|
|
40
|
+
basemaps.push(basemap);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.error(`The basemap ${sharedBasemap.name} could not be deserialized`);
|
|
44
|
+
}
|
|
36
45
|
}
|
|
46
|
+
return basemaps;
|
|
37
47
|
}
|
|
38
48
|
}
|
|
@@ -26,7 +26,7 @@ describe('ActiveBasemapsSerializer.serialize', () => {
|
|
|
26
26
|
})
|
|
27
27
|
];
|
|
28
28
|
const serialized = serializer.brainSerialize(basemaps);
|
|
29
|
-
expect(serialized).
|
|
29
|
+
expect(serialized).toEqual('[{"id":1,"name":"OpenStreetMap","opacity":-1}]');
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
32
|
describe('ActiveBasemapsSerializer.deserialize', () => {
|
|
@@ -40,13 +40,14 @@ describe('ActiveBasemapsSerializer.deserialize', () => {
|
|
|
40
40
|
basemaps.forEach((basemap) => {
|
|
41
41
|
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
42
42
|
});
|
|
43
|
-
serializer.brainDeserialize('1
|
|
43
|
+
serializer.brainDeserialize('[{"id":1,"name":"OpenStreetMap","opacity":-1}]');
|
|
44
44
|
const state = context.stateManager.state;
|
|
45
45
|
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
46
46
|
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
47
47
|
expect(state.activeBasemaps[0].opacity).toBe(-1);
|
|
48
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeTruthy();
|
|
48
49
|
});
|
|
49
|
-
it('
|
|
50
|
+
it('should deserialize a valid basemap even if another one cannot be found', () => {
|
|
50
51
|
const basemaps = [
|
|
51
52
|
new Basemap({
|
|
52
53
|
id: 1,
|
|
@@ -56,6 +57,87 @@ describe('ActiveBasemapsSerializer.deserialize', () => {
|
|
|
56
57
|
basemaps.forEach((basemap) => {
|
|
57
58
|
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
58
59
|
});
|
|
59
|
-
|
|
60
|
+
serializer.brainDeserialize('[{"id":1,"name":"OpenStreetMap","opacity":-1},{"id":2,"name":"NotExisting","opacity":0.5}]');
|
|
61
|
+
const state = context.stateManager.state;
|
|
62
|
+
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
63
|
+
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
64
|
+
expect(state.activeBasemaps[0].opacity).toBe(-1);
|
|
65
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeTruthy();
|
|
66
|
+
});
|
|
67
|
+
it('should deserialize a valid basemap with the right opacity', () => {
|
|
68
|
+
const basemaps = [
|
|
69
|
+
new Basemap({
|
|
70
|
+
id: 1,
|
|
71
|
+
name: 'OpenStreetMap'
|
|
72
|
+
})
|
|
73
|
+
];
|
|
74
|
+
basemaps.forEach((basemap) => {
|
|
75
|
+
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
76
|
+
});
|
|
77
|
+
serializer.brainDeserialize('[{"id":1,"name":"OpenStreetMap","opacity":0.45}]');
|
|
78
|
+
const state = context.stateManager.state;
|
|
79
|
+
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
80
|
+
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
81
|
+
expect(state.activeBasemaps[0].opacity).toBe(0.45);
|
|
82
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeFalsy();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('ActiveBasemapsSerializer.deserialize (preferNames)', () => {
|
|
86
|
+
beforeAll(() => {
|
|
87
|
+
context.configManager.Config.share.preferNames = true;
|
|
88
|
+
});
|
|
89
|
+
afterAll(() => {
|
|
90
|
+
context.configManager.Config.share.preferNames = false;
|
|
91
|
+
});
|
|
92
|
+
it('should deserialize a valid basemap id and set it as activeBasemap (preferNames)', () => {
|
|
93
|
+
const basemaps = [
|
|
94
|
+
new Basemap({
|
|
95
|
+
id: 1,
|
|
96
|
+
name: 'OpenStreetMap'
|
|
97
|
+
})
|
|
98
|
+
];
|
|
99
|
+
basemaps.forEach((basemap) => {
|
|
100
|
+
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
101
|
+
});
|
|
102
|
+
serializer.brainDeserialize('[{"id":999,"name":"OpenStreetMap","opacity":-1}]');
|
|
103
|
+
const state = context.stateManager.state;
|
|
104
|
+
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
105
|
+
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
106
|
+
expect(state.activeBasemaps[0].opacity).toBe(-1);
|
|
107
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeTruthy();
|
|
108
|
+
});
|
|
109
|
+
it('should deserialize a valid basemap even if another one cannot be found (preferNames)', () => {
|
|
110
|
+
const basemaps = [
|
|
111
|
+
new Basemap({
|
|
112
|
+
id: 1,
|
|
113
|
+
name: 'OpenStreetMap'
|
|
114
|
+
})
|
|
115
|
+
];
|
|
116
|
+
basemaps.forEach((basemap) => {
|
|
117
|
+
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
118
|
+
});
|
|
119
|
+
serializer.brainDeserialize('[{"id":999,"name":"OpenStreetMap","opacity":-1},{"id":888,"name":"NotExisting","opacity":0.5}]');
|
|
120
|
+
const state = context.stateManager.state;
|
|
121
|
+
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
122
|
+
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
123
|
+
expect(state.activeBasemaps[0].opacity).toBe(-1);
|
|
124
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeTruthy();
|
|
125
|
+
});
|
|
126
|
+
it('should deserialize a valid basemap with the right opacity (preferNames)', () => {
|
|
127
|
+
const basemaps = [
|
|
128
|
+
new Basemap({
|
|
129
|
+
id: 1,
|
|
130
|
+
name: 'OpenStreetMap'
|
|
131
|
+
})
|
|
132
|
+
];
|
|
133
|
+
basemaps.forEach((basemap) => {
|
|
134
|
+
context.stateManager.state.basemaps[basemap.id] = basemap;
|
|
135
|
+
});
|
|
136
|
+
serializer.brainDeserialize('[{"id":999,"name":"OpenStreetMap","opacity":0.45}]');
|
|
137
|
+
const state = context.stateManager.state;
|
|
138
|
+
expect(state.activeBasemaps).toBeInstanceOf((Array));
|
|
139
|
+
expect(state.activeBasemaps[0].id).toBe(basemaps[0].id);
|
|
140
|
+
expect(state.activeBasemaps[0].opacity).toBe(0.45);
|
|
141
|
+
expect(state.activeBasemaps[0].opacityDisabled).toBeFalsy();
|
|
60
142
|
});
|
|
61
143
|
});
|
|
@@ -7,6 +7,7 @@ export default class LayersConfigSerializer implements IBrainSerializer<LayersCo
|
|
|
7
7
|
private readonly context;
|
|
8
8
|
constructor(context: IGirafeContext);
|
|
9
9
|
private get state();
|
|
10
|
+
private get preferNames();
|
|
10
11
|
brainSerialize(layersConfig: LayersConfig): string;
|
|
11
12
|
protected serialize(layers: BaseLayer[]): string;
|
|
12
13
|
brainDeserialize(str: string): void;
|
|
@@ -16,6 +17,7 @@ export default class LayersConfigSerializer implements IBrainSerializer<LayersCo
|
|
|
16
17
|
private getExternalSerializedTheme;
|
|
17
18
|
private getExternalSerializedLayer;
|
|
18
19
|
private getInternalSerializedGroupOrTheme;
|
|
20
|
+
private getInternalLayerType;
|
|
19
21
|
private getInternalSerializedLayer;
|
|
20
22
|
private getDeserializedLayerTree;
|
|
21
23
|
private deserializeInternalObject;
|
|
@@ -24,8 +26,11 @@ export default class LayersConfigSerializer implements IBrainSerializer<LayersCo
|
|
|
24
26
|
private deserializeInternalLayer;
|
|
25
27
|
private checkUnknownLayers;
|
|
26
28
|
private removeUnnecessaryChilds;
|
|
29
|
+
private reorderChildren;
|
|
27
30
|
private findBaseLayerById;
|
|
28
|
-
private
|
|
31
|
+
private findLayerRecursiveById;
|
|
32
|
+
private findBaseLayerByName;
|
|
33
|
+
private findLayerRecursiveByName;
|
|
29
34
|
private deserializeExternalObject;
|
|
30
35
|
private deserializeExternalTheme;
|
|
31
36
|
private deserializeExternalWmsLayer;
|
|
@@ -7,6 +7,11 @@ import ThemeLayerExternal from '../../../models/layers/themelayerexternal.js';
|
|
|
7
7
|
import LayerWmsExternal from '../../../models/layers/layerwmsexternal.js';
|
|
8
8
|
import LayerWmtsExternal from '../../../models/layers/layerwmtsexternal.js';
|
|
9
9
|
import ServerOgc from '../../../models/serverogc.js';
|
|
10
|
+
import LayerWmts from '../../../models/layers/layerwmts.js';
|
|
11
|
+
import LayerVectorTiles from '../../../models/layers/layervectortiles.js';
|
|
12
|
+
import LayerCog from '../../../models/layers/layercog.js';
|
|
13
|
+
import LayerOsm from '../../../models/layers/layerosm.js';
|
|
14
|
+
import LayerXYZ from '../../../models/layers/layerxyz.js';
|
|
10
15
|
export default class LayersConfigSerializer {
|
|
11
16
|
context;
|
|
12
17
|
constructor(context) {
|
|
@@ -15,6 +20,9 @@ export default class LayersConfigSerializer {
|
|
|
15
20
|
get state() {
|
|
16
21
|
return this.context.stateManager.state;
|
|
17
22
|
}
|
|
23
|
+
get preferNames() {
|
|
24
|
+
return this.context.configManager.Config.share?.preferNames ?? false;
|
|
25
|
+
}
|
|
18
26
|
brainSerialize(layersConfig) {
|
|
19
27
|
return this.serialize(layersConfig.layersList);
|
|
20
28
|
}
|
|
@@ -104,6 +112,7 @@ export default class LayersConfigSerializer {
|
|
|
104
112
|
const originalTheme = this.context.themesHelper.findBaseLayerById(group.id);
|
|
105
113
|
const sharedChildren = [];
|
|
106
114
|
const removedChildrenIds = [];
|
|
115
|
+
const removedChildrenNames = [];
|
|
107
116
|
for (const originalChild of originalTheme.children) {
|
|
108
117
|
const index = group.children.findIndex((el) => el.id === originalChild.id);
|
|
109
118
|
if (index >= 0) {
|
|
@@ -114,6 +123,7 @@ export default class LayersConfigSerializer {
|
|
|
114
123
|
else {
|
|
115
124
|
// Element is not in the list any more, and therefore should not be shared or restored
|
|
116
125
|
removedChildrenIds.push(originalChild.id);
|
|
126
|
+
removedChildrenNames.push(originalChild.name);
|
|
117
127
|
}
|
|
118
128
|
}
|
|
119
129
|
return {
|
|
@@ -123,9 +133,39 @@ export default class LayersConfigSerializer {
|
|
|
123
133
|
isExpanded: Number(group.isExpanded),
|
|
124
134
|
timeRestriction: isTimeAwareLayer(group) ? group.timeRestriction : undefined,
|
|
125
135
|
children: sharedChildren,
|
|
126
|
-
excludedChildrenIds: removedChildrenIds
|
|
136
|
+
excludedChildrenIds: removedChildrenIds,
|
|
137
|
+
name: group.name,
|
|
138
|
+
type: this.getInternalLayerType(group),
|
|
139
|
+
excludedChildrenNames: removedChildrenNames
|
|
127
140
|
};
|
|
128
141
|
}
|
|
142
|
+
getInternalLayerType(layer) {
|
|
143
|
+
if (layer instanceof ThemeLayer) {
|
|
144
|
+
return 'theme';
|
|
145
|
+
}
|
|
146
|
+
if (layer instanceof GroupLayer) {
|
|
147
|
+
return 'group';
|
|
148
|
+
}
|
|
149
|
+
if (layer instanceof LayerWms) {
|
|
150
|
+
return 'wms';
|
|
151
|
+
}
|
|
152
|
+
if (layer instanceof LayerWmts) {
|
|
153
|
+
return 'wmts';
|
|
154
|
+
}
|
|
155
|
+
if (layer instanceof LayerVectorTiles) {
|
|
156
|
+
return 'vt';
|
|
157
|
+
}
|
|
158
|
+
if (layer instanceof LayerCog) {
|
|
159
|
+
return 'cog';
|
|
160
|
+
}
|
|
161
|
+
if (layer instanceof LayerOsm) {
|
|
162
|
+
return 'osm';
|
|
163
|
+
}
|
|
164
|
+
if (layer instanceof LayerXYZ) {
|
|
165
|
+
return 'xyz';
|
|
166
|
+
}
|
|
167
|
+
throw new Error(`The layer ${layer.name} has an unknown type and cannot be shared.`);
|
|
168
|
+
}
|
|
129
169
|
getInternalSerializedLayer(layer) {
|
|
130
170
|
return {
|
|
131
171
|
id: layer.id,
|
|
@@ -137,7 +177,9 @@ export default class LayersConfigSerializer {
|
|
|
137
177
|
filter: layer instanceof LayerWms && this.context.layerManager.isLayerWithFilter(layer)
|
|
138
178
|
? layer.filter
|
|
139
179
|
: undefined,
|
|
140
|
-
timeRestriction: isTimeAwareLayer(layer) ? layer.timeRestriction : undefined
|
|
180
|
+
timeRestriction: isTimeAwareLayer(layer) ? layer.timeRestriction : undefined,
|
|
181
|
+
name: layer.name,
|
|
182
|
+
type: this.getInternalLayerType(layer)
|
|
141
183
|
};
|
|
142
184
|
}
|
|
143
185
|
getDeserializedLayerTree(sharedLayers) {
|
|
@@ -146,7 +188,12 @@ export default class LayersConfigSerializer {
|
|
|
146
188
|
let layer;
|
|
147
189
|
if ('id' in sharedLayer) {
|
|
148
190
|
// Id attribute found => we are on an internal layer
|
|
149
|
-
|
|
191
|
+
if (this.preferNames && sharedLayer.name) {
|
|
192
|
+
layer = this.findBaseLayerByName(sharedLayer.name, sharedLayer.type);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
layer = this.findBaseLayerById(sharedLayer.id);
|
|
196
|
+
}
|
|
150
197
|
if (layer) {
|
|
151
198
|
this.deserializeInternalObject(layer, sharedLayer);
|
|
152
199
|
}
|
|
@@ -228,7 +275,9 @@ export default class LayersConfigSerializer {
|
|
|
228
275
|
let reorder = false;
|
|
229
276
|
for (let i = originalLayer.children.length - 1; i >= 0; i--) {
|
|
230
277
|
const child = originalLayer.children[i];
|
|
231
|
-
const serializedChild =
|
|
278
|
+
const serializedChild = this.preferNames
|
|
279
|
+
? sharedLayer.children.find((l) => l.name == child.name)
|
|
280
|
+
: sharedLayer.children.find((l) => l.id == child.id);
|
|
232
281
|
if (serializedChild) {
|
|
233
282
|
this.deserializeInternalObject(child, serializedChild);
|
|
234
283
|
}
|
|
@@ -236,7 +285,9 @@ export default class LayersConfigSerializer {
|
|
|
236
285
|
// This child exists in the original layer, but not in the shared state.
|
|
237
286
|
// => If it is present in the x list, it was explicitely removed
|
|
238
287
|
// And we can remove it from the current object
|
|
239
|
-
const explicitlyRemoved =
|
|
288
|
+
const explicitlyRemoved = this.preferNames
|
|
289
|
+
? sharedLayer.excludedChildrenNames.find((name) => name == child.name)
|
|
290
|
+
: sharedLayer.excludedChildrenIds.find((id) => id == child.id);
|
|
240
291
|
if (explicitlyRemoved) {
|
|
241
292
|
originalLayer.children.splice(i, 1);
|
|
242
293
|
console.debug(`Layer ${child.name} was removed from initial state`);
|
|
@@ -253,23 +304,26 @@ export default class LayersConfigSerializer {
|
|
|
253
304
|
}
|
|
254
305
|
}
|
|
255
306
|
if (reorder) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
307
|
+
this.reorderChildren(originalLayer);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
reorderChildren(originalLayer) {
|
|
311
|
+
console.debug(`Reordering childs for layer ${originalLayer.name}`);
|
|
312
|
+
let order = 1;
|
|
313
|
+
for (const child of originalLayer.children) {
|
|
314
|
+
child.order = order++;
|
|
261
315
|
}
|
|
262
316
|
}
|
|
263
317
|
findBaseLayerById(layerId) {
|
|
264
318
|
for (const theme of Object.values(this.state.themes._allThemes)) {
|
|
265
|
-
const layer = this.
|
|
319
|
+
const layer = this.findLayerRecursiveById(theme, layerId);
|
|
266
320
|
if (layer) {
|
|
267
321
|
return layer;
|
|
268
322
|
}
|
|
269
323
|
}
|
|
270
324
|
return null;
|
|
271
325
|
}
|
|
272
|
-
|
|
326
|
+
findLayerRecursiveById(layer, layerId) {
|
|
273
327
|
if (layer.id === layerId) {
|
|
274
328
|
// When deserializing the layer, we clone it,
|
|
275
329
|
// otherwise the following operation will also
|
|
@@ -280,7 +334,35 @@ export default class LayersConfigSerializer {
|
|
|
280
334
|
// Else, we call recursively on the children
|
|
281
335
|
if (layer instanceof GroupLayer || layer instanceof ThemeLayer) {
|
|
282
336
|
for (const childLayer of layer.children) {
|
|
283
|
-
const foundChild = this.
|
|
337
|
+
const foundChild = this.findLayerRecursiveById(childLayer, layerId);
|
|
338
|
+
if (foundChild) {
|
|
339
|
+
return foundChild;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
findBaseLayerByName(layerName, layerType) {
|
|
346
|
+
for (const theme of Object.values(this.state.themes._allThemes)) {
|
|
347
|
+
const layer = this.findLayerRecursiveByName(theme, layerName, layerType);
|
|
348
|
+
if (layer) {
|
|
349
|
+
return layer;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
findLayerRecursiveByName(layer, layerName, layerType) {
|
|
355
|
+
if (layer.name === layerName && this.getInternalLayerType(layer) === layerType) {
|
|
356
|
+
// When deserializing the layer, we clone it,
|
|
357
|
+
// otherwise the following operation will also
|
|
358
|
+
// affect the layer referenced in other themes
|
|
359
|
+
const foundLayer = layer.clone();
|
|
360
|
+
return foundLayer;
|
|
361
|
+
}
|
|
362
|
+
// Else, we call recursively on the children
|
|
363
|
+
if (layer instanceof GroupLayer || layer instanceof ThemeLayer) {
|
|
364
|
+
for (const childLayer of layer.children) {
|
|
365
|
+
const foundChild = this.findLayerRecursiveByName(childLayer, layerName, layerType);
|
|
284
366
|
if (foundChild) {
|
|
285
367
|
return foundChild;
|
|
286
368
|
}
|
|
@@ -74,10 +74,16 @@ function getTestData(options = {}) {
|
|
|
74
74
|
checked: options.isGroupChecked ? 1 : 0,
|
|
75
75
|
isExpanded: options.isGroupExpanded ? 1 : 0,
|
|
76
76
|
children: [],
|
|
77
|
-
excludedChildrenIds: options.addSecondMissingLayer ? [22] : []
|
|
77
|
+
excludedChildrenIds: options.addSecondMissingLayer ? [22] : [],
|
|
78
|
+
name: 'Group 1',
|
|
79
|
+
type: 'group',
|
|
80
|
+
excludedChildrenNames: options.addSecondMissingLayer ? ['Layer WMTS 2'] : []
|
|
78
81
|
}
|
|
79
82
|
],
|
|
80
|
-
excludedChildrenIds: options.addSecondMissingGroup ? [12] : []
|
|
83
|
+
excludedChildrenIds: options.addSecondMissingGroup ? [12] : [],
|
|
84
|
+
name: 'test-theme',
|
|
85
|
+
type: 'theme',
|
|
86
|
+
excludedChildrenNames: options.addSecondMissingGroup ? ['Group 2'] : []
|
|
81
87
|
}
|
|
82
88
|
];
|
|
83
89
|
if (options.addWmtsLayer) {
|
|
@@ -87,7 +93,9 @@ function getTestData(options = {}) {
|
|
|
87
93
|
checked: 0,
|
|
88
94
|
isExpanded: 0,
|
|
89
95
|
opacity: options.opacity ?? 1,
|
|
90
|
-
swiped: options.swiped ?? 'no'
|
|
96
|
+
swiped: options.swiped ?? 'no',
|
|
97
|
+
name: 'Layer WMTS 1',
|
|
98
|
+
type: 'wmts'
|
|
91
99
|
});
|
|
92
100
|
}
|
|
93
101
|
return {
|
|
@@ -269,6 +277,70 @@ describe('LayersConfigSerializer.deserialize', () => {
|
|
|
269
277
|
expect(serialized).toEqual(data.controlValue);
|
|
270
278
|
});
|
|
271
279
|
});
|
|
280
|
+
describe('LayersConfigSerializer.deserialize (preferNames)', () => {
|
|
281
|
+
beforeAll(() => {
|
|
282
|
+
context.configManager.Config.share.preferNames = true;
|
|
283
|
+
});
|
|
284
|
+
afterAll(() => {
|
|
285
|
+
context.configManager.Config.share.preferNames = false;
|
|
286
|
+
});
|
|
287
|
+
it('should return serialized data for a GroupLayer (id, order) (preferNames)', () => {
|
|
288
|
+
const data = getTestData();
|
|
289
|
+
serializer.brainDeserialize(data.controlValue);
|
|
290
|
+
const layersConfig = context.stateManager.state.layers;
|
|
291
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
292
|
+
expect(serialized).toEqual(data.controlValue);
|
|
293
|
+
});
|
|
294
|
+
it('should return serialized data for a GroupLayer (isExpanded) (preferNames)', () => {
|
|
295
|
+
const data = getTestData({ isGroupExpanded: true });
|
|
296
|
+
serializer.brainDeserialize(data.controlValue);
|
|
297
|
+
const layersConfig = context.stateManager.state.layers;
|
|
298
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
299
|
+
expect(serialized).toEqual(data.controlValue);
|
|
300
|
+
});
|
|
301
|
+
it('should return serialized data for a GroupLayer with children (preferNames)', () => {
|
|
302
|
+
const data = getTestData({ addWmtsLayer: true });
|
|
303
|
+
serializer.brainDeserialize(data.controlValue);
|
|
304
|
+
const layersConfig = context.stateManager.state.layers;
|
|
305
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
306
|
+
expect(serialized).toEqual(data.controlValue);
|
|
307
|
+
});
|
|
308
|
+
it('should return serialized data for a GroupLayer with children (opacity) (preferNames)', () => {
|
|
309
|
+
const data = getTestData({ addWmtsLayer: true, opacity: 0.5 });
|
|
310
|
+
serializer.brainDeserialize(data.controlValue);
|
|
311
|
+
const layersConfig = context.stateManager.state.layers;
|
|
312
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
313
|
+
expect(serialized).toEqual(data.controlValue);
|
|
314
|
+
});
|
|
315
|
+
it('should return serialized data for a GroupLayer with children (swiped left) (preferNames)', () => {
|
|
316
|
+
const data = getTestData({ addWmtsLayer: true, swiped: 'left' });
|
|
317
|
+
serializer.brainDeserialize(data.controlValue);
|
|
318
|
+
const layersConfig = context.stateManager.state.layers;
|
|
319
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
320
|
+
expect(serialized).toEqual(data.controlValue);
|
|
321
|
+
});
|
|
322
|
+
it('should return serialized data for a GroupLayer with children (swiped right) (preferNames)', () => {
|
|
323
|
+
const data = getTestData({ addWmtsLayer: true, swiped: 'left' });
|
|
324
|
+
serializer.brainDeserialize(data.controlValue);
|
|
325
|
+
const layersConfig = context.stateManager.state.layers;
|
|
326
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
327
|
+
expect(serialized).toEqual(data.controlValue);
|
|
328
|
+
});
|
|
329
|
+
it('should serialize a missing original group correctly (explicitely removed) (preferNames)', () => {
|
|
330
|
+
const data = getTestData({ addSecondMissingGroup: true });
|
|
331
|
+
serializer.brainDeserialize(data.controlValue);
|
|
332
|
+
const layersConfig = context.stateManager.state.layers;
|
|
333
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
334
|
+
expect(serialized).toEqual(data.controlValue);
|
|
335
|
+
});
|
|
336
|
+
it('should serialize a missing original layer correctly (explicitely removed) (preferNames)', () => {
|
|
337
|
+
const data = getTestData({ addWmtsLayer: true, addSecondMissingLayer: true });
|
|
338
|
+
serializer.brainDeserialize(data.controlValue);
|
|
339
|
+
const layersConfig = context.stateManager.state.layers;
|
|
340
|
+
const serialized = serializer.brainSerialize(layersConfig);
|
|
341
|
+
expect(serialized).toEqual(data.controlValue);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
272
344
|
describe('LayersConfigSerializer.serialize external', () => {
|
|
273
345
|
it('should return serialized data for an external theme', () => {
|
|
274
346
|
const data = getExternalTestData();
|
|
@@ -20,6 +20,16 @@ export type SharedInternalTheme = {
|
|
|
20
20
|
* Or if it was explicitly removed from the user, and then we won't have to display it again
|
|
21
21
|
*/
|
|
22
22
|
excludedChildrenIds: number[];
|
|
23
|
+
/**
|
|
24
|
+
* When configuring the share with "preferNames=true", the name of the layer will be used to generate the sahred state
|
|
25
|
+
* instead of the ID. But in this case, we also have to share the type os the layer, because tha layer name can be
|
|
26
|
+
* the same for a them, a group, a WMS-Layer, a WMTSLayer, etc...
|
|
27
|
+
* Also note that the "excludedChildrenNames" options has some limitations : if we have 2 layers of different types with the same name
|
|
28
|
+
* And if one of it is exceluded, both will be excluded.
|
|
29
|
+
*/
|
|
30
|
+
name: string;
|
|
31
|
+
type: string;
|
|
32
|
+
excludedChildrenNames: string[];
|
|
23
33
|
};
|
|
24
34
|
export type SharedInternalGroup = {
|
|
25
35
|
id: number;
|
|
@@ -29,6 +39,9 @@ export type SharedInternalGroup = {
|
|
|
29
39
|
timeRestriction?: string;
|
|
30
40
|
children: SharedInternalLayer[];
|
|
31
41
|
excludedChildrenIds: number[];
|
|
42
|
+
name: string;
|
|
43
|
+
type: string;
|
|
44
|
+
excludedChildrenNames: string[];
|
|
32
45
|
};
|
|
33
46
|
export type SharedInternalLayer = {
|
|
34
47
|
id: number;
|
|
@@ -39,6 +52,8 @@ export type SharedInternalLayer = {
|
|
|
39
52
|
opacity?: number;
|
|
40
53
|
swiped?: 'left' | 'right' | 'no';
|
|
41
54
|
filter?: SharedFilter;
|
|
55
|
+
name: string;
|
|
56
|
+
type: string;
|
|
42
57
|
};
|
|
43
58
|
export type SharedExternalTheme = {
|
|
44
59
|
name: string;
|
|
@@ -64,3 +79,8 @@ export type SharedExternalLayer = {
|
|
|
64
79
|
opacity?: number;
|
|
65
80
|
swiped?: 'left' | 'right' | 'no';
|
|
66
81
|
};
|
|
82
|
+
export type SharedBasemap = {
|
|
83
|
+
id: number;
|
|
84
|
+
name: string;
|
|
85
|
+
opacity: number;
|
|
86
|
+
};
|