Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…form/geoview into 1872-manage-escape-key
  • Loading branch information
kaminderpal committed Sep 27, 2024
2 parents 376f0b2 + 6ac8c8d commit d0cdcc0
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 59 deletions.
48 changes: 20 additions & 28 deletions packages/geoview-core/public/datasets/geojson/metadata-new.meta
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,11 @@
}
},
"style": {
"Point": {
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
}
},
Expand Down Expand Up @@ -338,13 +336,11 @@
}
},
"style": {
"Point": {
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
}
},
Expand Down Expand Up @@ -397,13 +393,11 @@
}
},
"style": {
"Point": {
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
}
},
Expand Down Expand Up @@ -456,13 +450,11 @@
}
},
"style": {
"Point": {
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
"styleType": "simple",
"label": "Point label",
"settings": {
"type": "simpleSymbol",
"symbol": "star"
}
}
}
Expand Down
71 changes: 70 additions & 1 deletion packages/geoview-core/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export class API {
// utilities object
utilities;

// Keep all callback delegates references
#onMapViewerReadyHandlers: MapViewerReadyDelegate[] = [];

// Keep all callback delegates references
#onMapAddedToDivHandlers: MapAddedToDivDelegate[] = [];

Expand All @@ -54,6 +57,32 @@ export class API {
API.#manageKeyboardFocus();
}

// TODO Add getter function and make maps property private
/**
* Sets a map viewer in maps, or removes one if the mapViewer property is null.
* @param {string} mapId - ID of the map
* @param {MapViewer | null} mapViewer - The viewer to be added or null to remove
* @param {(mapViewer: MapViewer) => void} onMapViewerInit - Function to run on map init
*/
setMapViewer(mapId: string, mapViewer: MapViewer | null, onMapViewerInit?: (mapViewer: MapViewer) => void): void {
if (mapViewer) {
if (this.maps[mapId]) logger.logError(`Cannot add map. Map with ID ${mapId} already exists`);
else {
this.maps[mapId] = mapViewer;

// Register a handler (which will only happen once) for when the map viewer will get initialized.
// At the time of writing, this happens later, asynchronously, via the components/map/map.tsx when 'MapViewer.initMap()' is called.
// That should be fixed eventually, but that refactoring is out of the scope at the time of writing. So, I'm doing like this for now.
this.maps[mapId].onMapInit((viewer) => {
// MapViewer has been created and initialized, callback about it
onMapViewerInit?.(viewer);
// Emit that viewer is ready
this.#emitMapViewerReady({ mapId });
});
}
} else delete this.maps[mapId];
}

/**
* Apply outline to elements when keyboard is use to navigate
* Code from: https://github.com/MaxMaeder/keyboardFocus.js
Expand Down Expand Up @@ -123,6 +152,33 @@ export class API {
return Promise.reject(new Error(`Div with id ${divId} does not exist`));
}

/**
* Emits a map viewer ready event to all handlers.
* @private
*/
#emitMapViewerReady(event: MapViewerReadyEvent): void {
// Emit the event for all handlers
EventHelper.emitEvent(this, this.#onMapViewerReadyHandlers, event);
}

/**
* Registers a map viewer ready event callback.
* @param {MapViewerReadyDelegate} callback - The callback to be executed whenever the event is emitted
*/
onMapViewerReady(callback: MapViewerReadyDelegate): void {
// Register the event handler
EventHelper.onEvent(this.#onMapViewerReadyHandlers, callback);
}

/**
* Unregisters a map viewer ready event callback.
* @param {MapViewerReadyDelegate} callback - The callback to stop being called whenever the event is emitted
*/
offMapViewerReady(callback: MapViewerReadyDelegate): void {
// Unregister the event handler
EventHelper.offEvent(this.#onMapViewerReadyHandlers, callback);
}

/**
* Emits an event to all handlers.
* @param {MapAddedToDivEvent} event - The event to emit
Expand Down Expand Up @@ -152,6 +208,19 @@ export class API {
}
}

/**
* Define a delegate for the event handler function signature
*/
type MapViewerReadyDelegate = EventDelegateBase<API, MapViewerReadyEvent, void>;

/**
* Define an event for the delegate
*/
export type MapViewerReadyEvent = {
// The added map
mapId: string;
};

/**
* Define a delegate for the event handler function signature
*/
Expand All @@ -161,6 +230,6 @@ type MapAddedToDivDelegate = EventDelegateBase<API, MapAddedToDivEvent, void>;
* Define an event for the delegate
*/
export type MapAddedToDivEvent = {
// The added layer
// The added map
mapId: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,15 @@ export class WmsLayerConfig extends AbstractGeoviewLayerConfig {
layerConfigsToQuery.forEach((layerConfig: WmsLayerEntryConfig, layerIndex: number) => {
// verify if the a request with the same layerId has already been sent up to now.
for (i = 0; layerConfigsToQuery[i].layerId !== layerConfig.layerId; i++);
if (i === layerIndex)
if (i === layerIndex) {
// if the layer found is the same as the current layer index,
// this is the first time we execute this request
promisedArrayOfMetadata.push(this.#executeServiceMetadataRequest(`${this.metadataAccessPath}?Layers=${layerConfig.layerId}`));
// otherwise, we are already waiting for the same request and we will wait for it to finish.
else promisedArrayOfMetadata.push(promisedArrayOfMetadata[i]);
const urlToQuery = this.metadataAccessPath.includes('?')
? `${this.metadataAccessPath}&Layers=${layerConfig.layerId}`
: `${this.metadataAccessPath}?Layers=${layerConfig.layerId}`;
promisedArrayOfMetadata.push(this.#executeServiceMetadataRequest(urlToQuery));
// otherwise, we are already waiting for the same request and we will wait for it to finish.
} else promisedArrayOfMetadata.push(promisedArrayOfMetadata[i]);
});

// Since we use Promise.all, If one of the Promise awaited fails, then the whole service metadata fetching will fail.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import cloneDeep from 'lodash/cloneDeep';

import { CV_DEFAULT_LAYER_INITIAL_SETTINGS } from '@config/types/config-constants';
import { TypeJsonObject } from '@config/types/config-types';
import { toJsonObject, TypeJsonObject } from '@config/types/config-types';
import { AbstractGeoviewLayerConfig } from '@config/types/classes/geoview-config/abstract-geoview-layer-config';
import { layerEntryIsGroupLayer } from '@config/types/type-guards';
import {
TypeGeoviewLayerType,
TypeLayerEntryType,
Expand Down Expand Up @@ -56,7 +57,7 @@ export abstract class EntryConfigBaseClass {
bounds: Extent | undefined;

/** Layer entry data type. */
entryType: TypeLayerEntryType;
entryType?: TypeLayerEntryType;

// GV NOTE START ****************************************************************************************************
// The following attributes use the 'definite assignment assertion' (! after the property name) to indicate that
Expand Down Expand Up @@ -151,16 +152,6 @@ export abstract class EntryConfigBaseClass {

// =================
// #region PROTECTED
/**
* The getter method that returns the language used to create the sublayer.
*
* @returns {TypeDisplayLanguage} The language associated to the config.
* @protected
*/
protected getLanguage(): TypeDisplayLanguage {
return this.#language;
}

/**
* Validate the node configuration using the schema associated to its layer type.
* @protected
Expand Down Expand Up @@ -197,6 +188,11 @@ export abstract class EntryConfigBaseClass {
return this.#geoviewLayerConfig.geoviewLayerType;
}

/** Set the geoview layer that owns this sub-layer configuration. */
setGeoviewLayerConfig(geoviewLayerConfig: AbstractGeoviewLayerConfig): void {
this.#geoviewLayerConfig = geoviewLayerConfig;
}

/** The geoview layer that owns this sub-layer configuration. */
getGeoviewLayerConfig(): AbstractGeoviewLayerConfig {
return this.#geoviewLayerConfig;
Expand All @@ -221,9 +217,11 @@ export abstract class EntryConfigBaseClass {
/**
* Method used to set the EntryConfigBaseClass error flag to true. Once this operation has been performed, the layer entry
* config is no longer considered viable.
*
* @param {boolean} value The value to assign to the flag.
*/
setErrorDetectedFlag(): void {
this.#errorDetectedFlag = true;
setErrorDetectedFlag(value = true): void {
this.#errorDetectedFlag = value;
}

/**
Expand All @@ -235,6 +233,15 @@ export abstract class EntryConfigBaseClass {
return this.#errorDetectedFlag;
}

/**
* Method used to set the parent node.
*
* @param {EntryConfigBaseClass | undefined} parentNode The parent node.
*/
setParentNode(parentNode: EntryConfigBaseClass | undefined): void {
this.#parentNode = parentNode;
}

/**
* The getter method that returns the parentNode.
*
Expand All @@ -244,6 +251,24 @@ export abstract class EntryConfigBaseClass {
return this.#parentNode;
}

/**
* The setter method that sets the language used to create the sublayer.
*
* @param {TypeDisplayLanguage} language The language associated to the config.
*/
setLanguage(language: TypeDisplayLanguage): void {
this.#language = language;
}

/**
* The getter method that returns the language used to create the sublayer.
*
* @returns {TypeDisplayLanguage} The language associated to the config.
*/
getLanguage(): TypeDisplayLanguage {
return this.#language;
}

/**
* This method returns the json string of the entry configuration. The output representation is a multi-line indented
* string. Indentation can be controled using the ident parameter. Private variables are not serialized.
Expand All @@ -264,6 +289,74 @@ export abstract class EntryConfigBaseClass {
this.minScale = 0;
this.maxScale = 0;
}

/**
* Create a clone of this node. This method is mainly used to clone a node from the layer tree to store a copy in the
* list of layer entry config of the GeoView Layer. It was created to preserve the private fields created using the #
* operator because cloneDeep doesn't copy them to the cloned instance.
*
* @param {EntryConfigBaseClass | undefined} parentNode The layer group that owns this node.
*
* @returns {EntryConfigBaseClass} The clone copy of the node.
*/
clone(parentNode: EntryConfigBaseClass | undefined = undefined): EntryConfigBaseClass {
let cloneOfTheNode: EntryConfigBaseClass = cloneDeep(this);

// Remove the following properties to avoid schema validation errors.
delete cloneOfTheNode.layerName;
delete cloneOfTheNode.entryType;
if ('listOfLayerEntryConfig' in cloneOfTheNode) cloneOfTheNode.listOfLayerEntryConfig = [];

// Create a new instance using the cloned config.
if (cloneOfTheNode.isLayerGroup)
cloneOfTheNode = this.#geoviewLayerConfig.createGroupNode(
toJsonObject(cloneOfTheNode),
this.#language,
this.#geoviewLayerConfig,
parentNode
)!;
else
cloneOfTheNode = this.#geoviewLayerConfig.createLeafNode(
toJsonObject(cloneOfTheNode),
this.#language,
this.#geoviewLayerConfig,
parentNode
)!;
// Restore the layerName and the private properties.
cloneOfTheNode.layerName = this.layerName;
cloneOfTheNode.setErrorDetectedFlag(this.#errorDetectedFlag);
cloneOfTheNode.setLayerMetadata(this.#layerMetadata);
return cloneOfTheNode;
}

/**
* The getter method that returns the sublayer configuration. If the layer path doesn't exists, return undefined.
*
* @returns {EntryConfigBaseClass | undefined} The sublayer configuration.
*/
getSubLayerConfig(layerPath: string): EntryConfigBaseClass | undefined {
// The node is a group
if (this.isLayerGroup && 'listOfLayerEntryConfig' in this) {
const pathItems = layerPath.split('/');
if (pathItems[0] !== this.layerId) return undefined;
if (pathItems.length === 1) return this;
let { listOfLayerEntryConfig } = this;
let nodeFound: EntryConfigBaseClass | undefined;
for (let i = 1; i < pathItems.length; i++) {
nodeFound = (listOfLayerEntryConfig as EntryConfigBaseClass[]).find(
(layerEntryConfig) => layerEntryConfig.layerId === pathItems[i]
);
if (!nodeFound) break;
listOfLayerEntryConfig = layerEntryIsGroupLayer(nodeFound) ? nodeFound.listOfLayerEntryConfig : [];
}
return nodeFound;
}

// The node is a leaf.
if (layerPath === this.layerId) return this;
return undefined;
}

// #endregion PUBLIC
// #endregion METHODS
// #endregion CLASS HEADER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
TypeViewSettings,
TypePointMarker,
} from '@config/types/map-schema-types';
import { cloneDeep } from 'lodash';
import { api } from '@/app';
import { LayerApi } from '@/geo/layer/layer';
import { MapViewer, TypeMapState, TypeMapMouseInfo } from '@/geo/map/map-viewer';
Expand Down Expand Up @@ -1050,7 +1051,9 @@ export class MapEventProcessor extends AbstractEventProcessor {
: undefined,
initialSettings,
style: legendLayerInfo!.styleConfig ? legendLayerInfo!.styleConfig : undefined,
source: (layerEntryConfig! as VectorLayerEntryConfig).source ? (layerEntryConfig! as VectorLayerEntryConfig).source : undefined,
source: (layerEntryConfig! as VectorLayerEntryConfig).source
? cloneDeep((layerEntryConfig! as VectorLayerEntryConfig).source)
: undefined,
entryType: listOfLayerEntryConfig.length ? 'group' : undefined,
listOfLayerEntryConfig: listOfLayerEntryConfig.length ? listOfLayerEntryConfig : [],
};
Expand Down
Loading

0 comments on commit d0cdcc0

Please sign in to comment.