@geogirafe/lib-geoportal 1.1.0-dev.2273215791 → 1.1.0-dev.2312792329

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.
@@ -6,6 +6,7 @@ declare class BasemapComponent extends GirafeHTMLElement {
6
6
  changeBasemap(basemap: Basemap): void;
7
7
  isBasemapActive(basemap: Basemap): boolean;
8
8
  determineClassnames(basemap: Basemap): "basemap-container active-basemap" | "basemap-container";
9
+ findBasemapByName(name: string): Basemap | undefined;
9
10
  changeBasemapOpacity(basemap: Basemap, e: PointerEvent): void;
10
11
  toggleVisibility(visible: boolean): void;
11
12
  registerEvents(): void;
@@ -48,6 +48,9 @@ class BasemapComponent extends GirafeHTMLElement {
48
48
  determineClassnames(basemap) {
49
49
  return this.isBasemapActive(basemap) ? 'basemap-container active-basemap' : 'basemap-container';
50
50
  }
51
+ findBasemapByName(name) {
52
+ return Object.values(this.state.basemaps).find((basemap) => basemap.name == name);
53
+ }
51
54
  changeBasemapOpacity(basemap, e) {
52
55
  e.stopPropagation();
53
56
  if (basemap.opacityDisabled) {
@@ -77,6 +80,17 @@ class BasemapComponent extends GirafeHTMLElement {
77
80
  }
78
81
  });
79
82
  this.subscribe('interface.basemapComponentVisible', (_oldValue, newValue) => this.toggleVisibility(newValue));
83
+ this.subscribe('functionalities.default_basemap', (_oldValue, newValue) => {
84
+ for (const defaultBasemapName of newValue) {
85
+ const defaultBasemap = this.findBasemapByName(defaultBasemapName == 'blank' ? 'Empty' : defaultBasemapName);
86
+ if (defaultBasemap) {
87
+ this.changeBasemap(defaultBasemap);
88
+ }
89
+ else {
90
+ console.warn(`BasemapComponent: Could not find Basemap '${defaultBasemapName}' to set by Functionality 'functionalities.default_basemap'`);
91
+ }
92
+ }
93
+ });
80
94
  }
81
95
  connectedCallback() {
82
96
  super.connectedCallback();
@@ -1,11 +1,17 @@
1
1
  import { Map } from 'ol';
2
2
  import olVectorTileLayer from 'ol/layer/VectorTile.js';
3
3
  import LayerVectorTiles from '../../../models/layers/layervectortiles.js';
4
+ import LayerGroup from 'ol/layer/Group.js';
4
5
  declare class VectorTilesManager {
5
6
  map: Map;
6
- basemapLayers: olVectorTileLayer[];
7
+ basemapLayers: (olVectorTileLayer | LayerGroup)[];
7
8
  constructor(map: Map);
8
9
  removeAllBasemapLayers(): void;
10
+ /**
11
+ * Adds a vectortiles basemap based on its layerName. If no layerName is provided,
12
+ * will use apply from ol-mapbox-style to create all layers.
13
+ * @param basemap
14
+ */
9
15
  addBasemapLayer(basemap: LayerVectorTiles): void;
10
16
  }
11
17
  export default VectorTilesManager;
@@ -1,5 +1,6 @@
1
1
  import olVectorTileLayer from 'ol/layer/VectorTile.js';
2
- import { applyStyle } from 'ol-mapbox-style';
2
+ import apply, { applyStyle } from 'ol-mapbox-style';
3
+ import LayerGroup from 'ol/layer/Group.js';
3
4
  class VectorTilesManager {
4
5
  map;
5
6
  basemapLayers = [];
@@ -12,9 +13,21 @@ class VectorTilesManager {
12
13
  });
13
14
  this.basemapLayers = [];
14
15
  }
16
+ /**
17
+ * Adds a vectortiles basemap based on its layerName. If no layerName is provided,
18
+ * will use apply from ol-mapbox-style to create all layers.
19
+ * @param basemap
20
+ */
15
21
  addBasemapLayer(basemap) {
16
- const olayer = new olVectorTileLayer({ declutter: true });
17
- applyStyle(olayer, basemap.style, basemap.source);
22
+ let olayer;
23
+ if (basemap.layerName) {
24
+ olayer = new olVectorTileLayer({ declutter: true });
25
+ applyStyle(olayer, basemap.style, basemap.layerName);
26
+ }
27
+ else {
28
+ olayer = new LayerGroup();
29
+ apply(olayer, basemap.style);
30
+ }
18
31
  this.basemapLayers.push(olayer);
19
32
  // For basemap, set a minimal number (arbitrary defined to less than -5000)
20
33
  olayer.setZIndex(-5000 - basemap.order);
@@ -16,7 +16,7 @@ export default class BasemapSwisstopoVectorTiles extends Basemap {
16
16
  name: 'Swisstopo Vector-Tiles',
17
17
  metadata: { ...basemapMetadata }
18
18
  });
19
- const vectorTilesLayer = new LayerVectorTiles(LayerConsts.LayerSwisstopoVectorTilesId, 'Swisstopo Vector-Tiles', 0, 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/style.json', 'leichtebasiskarte_v3.0.1', { projection: 'EPSG:3857' });
19
+ const vectorTilesLayer = new LayerVectorTiles(LayerConsts.LayerSwisstopoVectorTilesId, 'Swisstopo Vector-Tiles', 0, 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.lightbasemap.vt/style.json', { projection: 'EPSG:3857' });
20
20
  this.layersList.push(vectorTilesLayer);
21
21
  }
22
22
  }
package/models/gmf.d.ts CHANGED
@@ -57,13 +57,15 @@ export interface GMFTreeItem {
57
57
  time?: ITimeOptions;
58
58
  public?: boolean;
59
59
  }
60
+ export type GMFThemeFunctionality = string | string[] | number | number[] | boolean | boolean[];
61
+ export interface GMFThemeFunctionalities {
62
+ [key: string]: GMFThemeFunctionality;
63
+ }
60
64
  export interface GMFTheme {
61
65
  id: number;
62
66
  name: string;
63
67
  icon: string;
64
- functionalities: {
65
- [key: string]: string;
66
- };
68
+ functionalities: GMFThemeFunctionalities;
67
69
  metadata: GMFMetadata;
68
70
  children: GMFTreeItem[];
69
71
  }
@@ -1,6 +1,7 @@
1
1
  import Layer from './layer.js';
2
2
  type LayerVectorTilesOptions = {
3
3
  projection?: string;
4
+ layerName?: string;
4
5
  isDefaultChecked?: boolean;
5
6
  disclaimer?: string;
6
7
  metadataUrl?: string;
@@ -16,9 +17,9 @@ declare class LayerVectorTiles extends Layer {
16
17
  * For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
17
18
  */
18
19
  style: string;
19
- source: string;
20
+ layerName?: string;
20
21
  projection?: string;
21
- constructor(id: number, name: string, order: number, style: string, source: string, options?: LayerVectorTilesOptions);
22
+ constructor(id: number, name: string, order: number, style: string, options?: LayerVectorTilesOptions);
22
23
  clone(): LayerVectorTiles;
23
24
  }
24
25
  export default LayerVectorTiles;
@@ -8,24 +8,25 @@ class LayerVectorTiles extends Layer {
8
8
  * For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
9
9
  */
10
10
  style;
11
- source;
11
+ layerName;
12
12
  projection;
13
- constructor(id, name, order, style, source, options) {
13
+ constructor(id, name, order, style, options) {
14
14
  super(id, name, order, options);
15
15
  this.style = style;
16
- this.source = source;
16
+ this.layerName = options?.layerName;
17
17
  this.projection = options?.projection;
18
18
  }
19
19
  clone() {
20
20
  const options = {
21
21
  projection: this.projection,
22
+ layerName: this.layerName,
22
23
  isDefaultChecked: this.isDefaultChecked,
23
24
  metadataUrl: this.metadataUrl,
24
25
  disclaimer: this.disclaimer,
25
26
  opacity: this.opacity,
26
27
  restricted: this.restricted
27
28
  };
28
- const clonedObject = new LayerVectorTiles(this.id, this.name, this.order, this.style, this.source, options);
29
+ const clonedObject = new LayerVectorTiles(this.id, this.name, this.order, this.style, options);
29
30
  clonedObject.activeState = this.activeState;
30
31
  return clonedObject;
31
32
  }
package/models/main.d.ts CHANGED
@@ -3,7 +3,7 @@ export { default as BasemapEmpty } from './basemaps/basemapempty.js';
3
3
  export { default as BasemapOsm } from './basemaps/basemaposm.js';
4
4
  export { default as BasemapSwisstopoVectorTiles } from './basemaps/basemapswisstopovectortiles.js';
5
5
  export { default as CustomTheme } from './customtheme.js';
6
- export type { GMFMetadata, GMFChildLayer, GMFTreeItem, GMFTheme, GMFGroup, GMFBackgroundLayer, GMFServerOgc, GMFServerOgcAttributes, GMFServerOgcObjectAttributes, GMFServerOgcColumnAttributes } from './gmf.js';
6
+ export type { GMFMetadata, GMFChildLayer, GMFTreeItem, GMFThemeFunctionality, GMFThemeFunctionalities, GMFTheme, GMFGroup, GMFBackgroundLayer, GMFServerOgc, GMFServerOgcAttributes, GMFServerOgcObjectAttributes, GMFServerOgcColumnAttributes } from './gmf.js';
7
7
  export { default as BaseLayer } from './layers/baselayer.js';
8
8
  export type { GroupLayerOptions } from './layers/grouplayer.js';
9
9
  export { default as GroupLayer } from './layers/grouplayer.js';
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geomapfish.dev"
7
7
  },
8
- "version": "1.1.0-dev.2273215791",
8
+ "version": "1.1.0-dev.2312792329",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -150,6 +150,7 @@
150
150
  "build-apk": "docker run -v ./dist:/geogirafe/dist -v ./buildtools:/geogirafe/buildtools geogirafe/cordova-builder bash -c \"cp /geogirafe/buildtools/cordova/apk-build.sh . && chmod u+x apk-build.sh && ./apk-build.sh\"",
151
151
  "build-apk-win": "docker run -v %cd%/dist:/geogirafe/dist -v %cd%/buildtools:/geogirafe/buildtools geogirafe/cordova-builder bash -c \"cp /geogirafe/buildtools/cordova/apk-build.sh . && chmod u+x apk-build.sh && ./apk-build.sh\"",
152
152
  "test": "vitest --run --coverage",
153
+ "test-without-coverage": "vitest --run",
153
154
  "test-watch": "vitest",
154
155
  "configure-demo": "bash -C './buildtools/configure-demo.sh'",
155
156
  "configure-demo-win": "buildtools\\configure-demo.cmd",
@@ -1 +1 @@
1
- {"version":"1.1.0-dev.2273215791", "build":"2273215791", "date":"20/01/2026"}
1
+ {"version":"1.1.0-dev.2312792329", "build":"2312792329", "date":"08/02/2026"}
@@ -22,7 +22,7 @@ function customDnsLookup(hostname, arg1, arg2) {
22
22
  const callback = typeof arg1 === 'function' ? arg1 : arg2;
23
23
  const options = typeof arg1 === 'function' ? undefined : arg1;
24
24
  if (hostname === 'app.localhost') {
25
- callback(null, '127.0.0.1', 4); // use '0.0.0.0' for being accessible from other devices on the network
25
+ callback(null, '0.0.0.0', 4); // use '0.0.0.0' for being accessible from other devices on the network
26
26
  } else {
27
27
  originalDnsLookup(hostname, options, callback);
28
28
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Known Functionalities which are allowed in <code>GMFTheme.functionalities</code> and are published to
3
+ * <code>State.functionalities</code>. Subscribe a Handler to get notified when a Theme which such a Functionality is
4
+ * selected by the User (e.g., Change the Basemap):
5
+ * <code>
6
+ * GirafeHTMLElement.subscribe('functionalities.default_basemap', (oldValue: string[], newValue: string[]) => {
7
+ * ...
8
+ * });
9
+ * </code>
10
+ */
11
+ export declare const KNOWN_FUNCTIONALITIES: string[];
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Known Functionalities which are allowed in <code>GMFTheme.functionalities</code> and are published to
3
+ * <code>State.functionalities</code>. Subscribe a Handler to get notified when a Theme which such a Functionality is
4
+ * selected by the User (e.g., Change the Basemap):
5
+ * <code>
6
+ * GirafeHTMLElement.subscribe('functionalities.default_basemap', (oldValue: string[], newValue: string[]) => {
7
+ * ...
8
+ * });
9
+ * </code>
10
+ */
11
+ export const KNOWN_FUNCTIONALITIES = ['default_basemap'];
package/tools/main.d.ts CHANGED
@@ -17,6 +17,7 @@ export { default as CsvManager } from './export/csvmanager.js';
17
17
  export { download } from './export/download.js';
18
18
  export type { GridDataById, GridData, FeatureToGridDataOptions } from './featuretogriddatabyid.js';
19
19
  export { default as FeatureToGridDataById } from './featuretogriddatabyid.js';
20
+ export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
20
21
  export { default as GeoConsts } from './geoconsts.js';
21
22
  export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
22
23
  export type { TranslationsDict } from './i18n/i18nmanager.js';
package/tools/main.js CHANGED
@@ -15,6 +15,7 @@ export { default as ErrorManager } from './error/errormanager.js';
15
15
  export { default as CsvManager } from './export/csvmanager.js';
16
16
  export { download } from './export/download.js';
17
17
  export { default as FeatureToGridDataById } from './featuretogriddatabyid.js';
18
+ export { KNOWN_FUNCTIONALITIES } from './functionalities.js';
18
19
  export { default as GeoConsts } from './geoconsts.js';
19
20
  export { formatCoordinates, parseCoordinates, decimalToDMS, printCoordinate } from './geometrytools.js';
20
21
  export { default as I18nManager } from './i18n/i18nmanager.js';
@@ -11,8 +11,10 @@ import type CustomTheme from '../../models/customtheme.js';
11
11
  import ObjectSelection from './objectselection.js';
12
12
  import type Theme from '../../models/theme.js';
13
13
  import GraphicalInterface from './graphicalInterface.js';
14
+ import { GMFThemeFunctionalities, GMFThemeFunctionality } from '../../models/gmf.js';
14
15
  export type ThemesConfig = {
15
16
  _allThemes: Record<number, ThemeLayer>;
17
+ _allFunctionalities: Record<number, GMFThemeFunctionalities>;
16
18
  isLoaded: boolean;
17
19
  lastSelectedTheme: ThemeLayer | CustomTheme | null;
18
20
  };
@@ -85,6 +87,7 @@ export default class State {
85
87
  * For example, any method doing <this.xxx = value> is forbidden here, because the modification be known from the proxy
86
88
  */
87
89
  themes: ThemesConfig;
90
+ functionalities: Record<string, GMFThemeFunctionality>;
88
91
  basemaps: Record<number, Basemap>;
89
92
  ogcServers: Record<string, ServerOgc>;
90
93
  activeBasemaps: Basemap[];
@@ -22,9 +22,11 @@ export default class State {
22
22
  // Dictionary where the key is the id of the theme
23
23
  themes = {
24
24
  _allThemes: {},
25
+ _allFunctionalities: {},
25
26
  isLoaded: false,
26
27
  lastSelectedTheme: null
27
28
  };
29
+ functionalities = {};
28
30
  // All basemaps from themes.json
29
31
  // Dictionary where the key is the id of the basemap
30
32
  basemaps = {};
@@ -7,7 +7,7 @@ export default class ThemesHelper extends GirafeSingleton {
7
7
  initializeSingleton(): void;
8
8
  private get state();
9
9
  findBaseLayerById(layerId: number): BaseLayer;
10
- private findBaseLayerRecurviveById;
10
+ private findBaseLayerRecursiveById;
11
11
  findThemeByName(themename: string): ThemeLayer | null;
12
12
  findGroupByName(groupname: string): GroupLayer | null;
13
13
  findLayerByName(layername: string): Layer | null;
@@ -6,6 +6,7 @@ import LayerWms from '../../models/layers/layerwms.js';
6
6
  import ThemeLayer from '../../models/layers/themelayer.js';
7
7
  import { isTimeAwareLayer } from '../../models/layers/timeawarelayer.js';
8
8
  import WfsFilter, { isWfsOperator } from '../wfs/wfsfilter.js';
9
+ import { KNOWN_FUNCTIONALITIES } from '../functionalities.js';
9
10
  export default class ThemesHelper extends GirafeSingleton {
10
11
  initializeSingleton() {
11
12
  this.context.stateManager.subscribe('themes.lastSelectedTheme', (_oldTheme, newTheme) => this.onSelectedThemeChanged(newTheme));
@@ -18,20 +19,20 @@ export default class ThemesHelper extends GirafeSingleton {
18
19
  if (theme.id === layerId) {
19
20
  return theme;
20
21
  }
21
- const child = this.findBaseLayerRecurviveById(theme.children, layerId);
22
+ const child = this.findBaseLayerRecursiveById(theme.children, layerId);
22
23
  if (child) {
23
24
  return child;
24
25
  }
25
26
  }
26
27
  throw new Error(`No BaseLayer with ID ${layerId} could be found.`);
27
28
  }
28
- findBaseLayerRecurviveById(layers, layerId) {
29
+ findBaseLayerRecursiveById(layers, layerId) {
29
30
  for (const layer of layers) {
30
31
  if (layer.id === layerId) {
31
32
  return layer;
32
33
  }
33
34
  if (layer instanceof GroupLayer || layer instanceof ThemeLayer) {
34
- const child = this.findBaseLayerRecurviveById(layer.children, layerId);
35
+ const child = this.findBaseLayerRecursiveById(layer.children, layerId);
35
36
  if (child) {
36
37
  return child;
37
38
  }
@@ -107,24 +108,37 @@ export default class ThemesHelper extends GirafeSingleton {
107
108
  }
108
109
  onThemeChanged(theme) {
109
110
  // Create a clone of the theme object to use it in the treeview.
110
- // This is essential, otherwise all changes done in the layers
111
- // (For example when expanding legend, expanding a group, or activating the layer)
112
- // Will also be done in the default layer configuration that has been loaded from themes.json
113
- // And when a theme will be selected aging from the themes-selector
111
+ // This is essential, otherwise all changes are done in the layers
112
+ // (For example, when expanding legend, expanding a group, or activating the layer).
113
+ // Will also be done in the default layer configuration that has been loaded from themes.json,
114
+ // And when a theme is selected aging from the themes-selector
114
115
  // The default configuration will have been overwritten.
115
116
  const clonedTheme = theme.clone();
117
+ const themeAlreadyInLayersList = this.state.layers.layersList.find((l) => l.id == clonedTheme.id);
118
+ if (themeAlreadyInLayersList) {
119
+ console.info(`The theme ${clonedTheme.name} is already present in the treeview.`);
120
+ return;
121
+ }
116
122
  if (this.context.configManager.Config.themes.selectionMode === 'replace') {
117
123
  // Mode is <replace>
118
124
  this.emptyLayerTree();
119
125
  this.state.layers.layersList.push(clonedTheme);
120
126
  }
121
- else if (!this.state.layers.layersList.find((l) => l.id == clonedTheme.id)) {
127
+ else {
122
128
  // Mode is <add>
123
129
  clonedTheme.order = this.getInitialOrderForNewTheme();
124
130
  this.state.layers.layersList.push(clonedTheme);
125
131
  }
126
- else {
127
- console.info(`The theme ${clonedTheme.name} is already present in the treeview.`);
132
+ const themeFunctionalities = this.state.themes._allFunctionalities[theme.id];
133
+ if (themeFunctionalities) {
134
+ Object.keys(themeFunctionalities).forEach((functionality) => {
135
+ if (KNOWN_FUNCTIONALITIES.includes(functionality)) {
136
+ this.state.functionalities[functionality] = themeFunctionalities[functionality];
137
+ }
138
+ else {
139
+ console.warn(`Unknown functionality '${functionality}' found on Theme '${theme.name}'.`);
140
+ }
141
+ });
128
142
  }
129
143
  }
130
144
  getMinimalClonedThemeForLayer(layer) {
@@ -167,3 +167,55 @@ describe('ThemesHelper.getInitialOrderForNewTheme', () => {
167
167
  expect(themesHelper.getInitialOrderForNewTheme()).toEqual(103);
168
168
  });
169
169
  });
170
+ describe('ThemesHelper.onSelectedThemeChanged', () => {
171
+ let stateManager;
172
+ const callbacks = [];
173
+ beforeEach(() => {
174
+ stateManager = context.stateManager;
175
+ for (const callback of callbacks) {
176
+ stateManager.unsubscribe(callback);
177
+ callbacks.splice(callbacks.indexOf(callback), 1);
178
+ }
179
+ });
180
+ it('should trigger change in functionalities if functionality is known', () => {
181
+ stateManager.state.themes._allFunctionalities = {
182
+ 42: {
183
+ default_basemap: ['blank']
184
+ }
185
+ };
186
+ let subscriptionCalled = false;
187
+ callbacks.push(stateManager.subscribe('functionalities.default_basemap', () => {
188
+ subscriptionCalled = true;
189
+ }));
190
+ stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
191
+ expect(subscriptionCalled).toBeTruthy();
192
+ });
193
+ it('should NOT trigger change in functionalities if functionality is not known', () => {
194
+ stateManager.state.themes._allFunctionalities = {
195
+ 42: {
196
+ unknown_functionality: 'Lorem Ipsum Dolor Sit Amet'
197
+ }
198
+ };
199
+ let subscriptionCalled = false;
200
+ callbacks.push(stateManager.subscribe('functionalities.unknown_functionality', (_oldValue, newValue) => {
201
+ console.log(newValue);
202
+ subscriptionCalled = true;
203
+ }));
204
+ stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
205
+ expect(subscriptionCalled).toBeFalsy();
206
+ });
207
+ it('should trigger change in functionalities.default_basemap with expected params', () => {
208
+ stateManager.state.themes._allFunctionalities = {
209
+ 42: {
210
+ default_basemap: ['blank']
211
+ }
212
+ };
213
+ let paramsCalledWith = undefined;
214
+ callbacks.push(stateManager.subscribe('functionalities.default_basemap', (_oldVal, newVal) => {
215
+ paramsCalledWith = newVal;
216
+ }));
217
+ stateManager.state.themes.lastSelectedTheme = new ThemeLayer(42, 'lastSelectedTheme', 101);
218
+ expect(paramsCalledWith).not.toBeUndefined();
219
+ expect(paramsCalledWith).toEqual(['blank']);
220
+ });
221
+ });
@@ -22,6 +22,9 @@ declare class ThemesManager extends GirafeSingleton {
22
22
  */
23
23
  private preloadWfsServer;
24
24
  private prepareBasemaps;
25
+ private addBasemapsFromConfig;
26
+ private applyOpacityToBasemaps;
27
+ private applyOpacityToBasemap;
25
28
  private prepareThemes;
26
29
  private calculateMetadataUrl;
27
30
  /**
@@ -96,7 +96,9 @@ class ThemesManager extends GirafeSingleton {
96
96
  const content = await response.json();
97
97
  this.state.ogcServers = this.prepareOgcServers(content['ogcServers']);
98
98
  this.state.basemaps = this.prepareBasemaps(content['background_layers']);
99
- this.state.themes._allThemes = this.prepareThemes(content['themes']);
99
+ const themesAndFunctionalities = this.prepareThemes(content['themes']);
100
+ this.state.themes._allThemes = themesAndFunctionalities.themes;
101
+ this.state.themes._allFunctionalities = themesAndFunctionalities.themesFunctionalities;
100
102
  this.context.customThemesManager.loadCustomThemes();
101
103
  this.state.themes.isLoaded = true;
102
104
  if (this.context.configManager.Config.themes.showErrorsOnStart) {
@@ -170,7 +172,12 @@ class ThemesManager extends GirafeSingleton {
170
172
  const basemapSwisstopoVectorTiles = new BasemapSwisstopoVectorTiles();
171
173
  basemaps[basemapSwisstopoVectorTiles.id] = basemapSwisstopoVectorTiles;
172
174
  }
173
- basemapJson.forEach((elem) => {
175
+ this.addBasemapsFromConfig(basemapJson, basemaps);
176
+ this.applyOpacityToBasemaps(basemaps);
177
+ return basemaps;
178
+ }
179
+ addBasemapsFromConfig(basemapsJson, basemaps) {
180
+ basemapsJson.forEach((elem) => {
174
181
  // Create basemap
175
182
  const basemap = new Basemap(elem);
176
183
  basemaps[basemap.id] = basemap;
@@ -193,34 +200,39 @@ class ThemesManager extends GirafeSingleton {
193
200
  }
194
201
  }
195
202
  });
196
- // Apply Opacity
203
+ }
204
+ applyOpacityToBasemaps(basemaps) {
197
205
  for (const basemap of Object.values(basemaps)) {
198
206
  if (this.context.configManager.Config.basemaps.opacityBasemaps.includes(basemap.name)) {
199
- // If it is the default Basemap the Opacity should NOT be 0 as otherwise the User would end up seeing nothing
200
- const isDefaultBasemap = this.context.configManager.Config.basemaps.defaultBasemap == basemap.name;
201
- basemap.opacity = isDefaultBasemap ? OPACITY_FOR_DEFAULT_BASEMAP : DEFAULT_OPACITY;
202
- for (const basemapLayer of basemap.layersList) {
203
- if (basemapLayer instanceof LayerVectorTiles) {
204
- // Vector tiles layers are not supported as opacitybasemap, because the tiles cannot reprojected on the fly
205
- // And displaying a basemap from some SRID with an VT from another SRID won't work
206
- // So for the moment we do not allow VT configured as opacitybasemaps
207
- // (But the opposite will still work : a VT basemap with a WMTS opacitybasemap)
208
- }
209
- if (basemapLayer instanceof Layer) {
210
- basemapLayer.opacity = basemap.opacity;
211
- }
212
- }
207
+ this.applyOpacityToBasemap(basemap);
208
+ }
209
+ }
210
+ }
211
+ applyOpacityToBasemap(basemap) {
212
+ // If it is the default Basemap the Opacity should NOT be 0 as otherwise the User would end up seeing nothing
213
+ const isDefaultBasemap = this.context.configManager.Config.basemaps.defaultBasemap == basemap.name;
214
+ basemap.opacity = isDefaultBasemap ? OPACITY_FOR_DEFAULT_BASEMAP : DEFAULT_OPACITY;
215
+ for (const basemapLayer of basemap.layersList) {
216
+ if (basemapLayer instanceof LayerVectorTiles) {
217
+ // Vector tiles layers are not supported as opacitybasemap, because the tiles cannot reprojected on the fly
218
+ // And displaying a basemap from some SRID with an VT from another SRID won't work
219
+ // So for the moment we do not allow VT configured as opacitybasemaps
220
+ // (But the opposite will still work : a VT basemap with a WMTS opacitybasemap)
221
+ }
222
+ else if (basemapLayer instanceof Layer) {
223
+ basemapLayer.opacity = basemap.opacity;
213
224
  }
214
225
  }
215
- return basemaps;
216
226
  }
217
227
  prepareThemes(themesJson) {
218
228
  const themes = {};
219
229
  const order = { value: 0 };
230
+ const themesFunctionalities = {};
220
231
  themesJson.forEach((themeJson, index) => {
221
232
  if (!themeJson.icon.startsWith('http') && this.context.configManager.Config.themes.imagesUrlPrefix) {
222
233
  themeJson.icon = this.context.configManager.Config.themes.imagesUrlPrefix + themeJson.icon;
223
234
  }
235
+ themesFunctionalities[themeJson.id] = themeJson['functionalities'];
224
236
  const theme = new ThemeLayer(themeJson['id'], themeJson['name'], index, themeJson['icon'], themeJson['metadata']);
225
237
  themeJson.children.forEach((layerJson) => {
226
238
  const layer = this.prepareThemeLayer(layerJson, null, order);
@@ -231,7 +243,7 @@ class ThemesManager extends GirafeSingleton {
231
243
  });
232
244
  themes[index] = theme;
233
245
  });
234
- return themes;
246
+ return { themes, themesFunctionalities };
235
247
  }
236
248
  calculateMetadataUrl(metadataUrl) {
237
249
  if (!metadataUrl) {
@@ -359,12 +371,13 @@ class ThemesManager extends GirafeSingleton {
359
371
  projection: 'EPSG:3857',
360
372
  isDefaultChecked: elem.metadata?.isChecked,
361
373
  disclaimer: elem.metadata?.disclaimer,
362
- metadata: elem.metadata
374
+ metadata: elem.metadata,
375
+ layerName: elem.metadata.layerName
363
376
  };
364
377
  if (options.metadata?.metadataUrl) {
365
378
  options.metadata.metadataUrl = this.calculateMetadataUrl(options.metadata.metadataUrl);
366
379
  }
367
- return new LayerVectorTiles(elem.id, elem.name, order.value, elem.style, elem.metadata.layerName, options);
380
+ return new LayerVectorTiles(elem.id, elem.name, order.value, elem.style, options);
368
381
  }
369
382
  return null;
370
383
  }