hslayers-ng
Version:
HSLayers-NG mapping library
315 lines (310 loc) • 13 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, inject } from '@angular/core';
import { Subject } from 'rxjs';
class HsConfigValidationService {
constructor() {
/**
* Default validation rules for detecting incompatible configuration combinations
*/
this.defaultValidationRules = [
{
condition: (config) => config.defaultComposition &&
config.panelsEnabled?.compositions === false,
message: 'defaultComposition requires compositions panel to be enabled',
},
{
condition: (config) => config.panelsEnabled?.sensors === true && !config.senslog?.url,
message: 'sensors panel requires senslog.url to be configured',
},
];
}
/**
* Validates configuration for incompatible combinations and returns warning messages
* @param config - The configuration object to validate
* @param userRules - Optional user-defined validation rules from config
* @param useDefaultRules - Whether to include default validation rules (default: true)
* @returns Array of warning messages for detected conflicts
*/
validate(config, userRules, useDefaultRules = true) {
const warnings = [];
try {
// Start with default rules if enabled
const allRules = useDefaultRules
? [...this.defaultValidationRules]
: [];
// Add user rules if provided
if (userRules && Array.isArray(userRules)) {
userRules.forEach((userRule) => {
// Validate user rule
if (!userRule.condition || !userRule.message) {
console.warn('HsConfigValidation Warning: Invalid validation rule provided. Rule must have condition and message properties.', userRule);
return;
}
allRules.push(userRule);
});
}
// Run validation with all rules
allRules.forEach((rule, index) => {
try {
if (rule.condition(config)) {
warnings.push(`Configuration conflict detected: ${rule.message}`);
}
}
catch (e) {
warnings.push(`Error in validation rule #${index + 1}: ${e.message}`);
}
});
}
catch (e) {
warnings.push(`Critical error during configuration validation: ${e.message}`);
}
return warnings;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfigValidationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfigValidationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfigValidationService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
class HsConfigObject {
constructor() {
/**
* Controls where toast notifications are anchored to
* 'screen' - anchors toasts to the viewport
* 'map' - anchors toasts to the map container
* @default 'map' - anchors toasts to the map container
*/
this.toastAnchor = 'map';
this.mapSwipeOptions = {};
this.pathExclusivity = false;
this.panelsEnabled = {
legend: true,
compositions: true,
measure: true,
draw: true,
layerManager: true,
print: true,
saveMap: true,
language: true,
share: true,
query: true,
sensors: false,
search: true,
tripPlanner: false,
addData: true,
mapSwipe: false,
wfsFilter: false,
};
this.componentsEnabled = {
guiOverlay: true,
info: true,
sidebar: true,
toolbar: true,
searchToolbar: true,
drawToolbar: true,
measureToolbar: true,
geolocationButton: true,
defaultViewButton: true,
mapControls: true,
basemapGallery: false,
// Says whether it should be activated by default. Is overridden by url param
mapSwipe: false,
queryPopup: true,
};
this.layerEditorWidgetsEnabled = true;
this.queryPopupWidgets = ['layer-name', 'feature-info', 'clear-layer'];
this.panelWidths = {
default: 425,
ows: 700,
compositions: 550,
addData: 700,
wfsFilter: 550,
mapSwipe: 550,
};
this.sidebarPosition = 'right';
this.sidebarToggleable = true;
this.mobileBreakpoint = 767;
}
}
class HsConfig extends HsConfigObject {
constructor() {
super(...arguments);
this.validationService = inject(HsConfigValidationService);
this.configChanges = new Subject();
this.defaultSymbolizerIcons = [
{ name: 'favourite', url: 'img/icons/favourite28.svg' },
{ name: 'gps', url: 'img/icons/gps43.svg' },
{ name: 'information', url: 'img/icons/information78.svg' },
{ name: 'wifi', url: 'img/icons/wifi8.svg' },
];
}
logConfigWarning(message) {
console.warn('HsConfig Warning:', message);
}
/**
* Validates configuration for incompatible combinations and logs warnings
* @param config - The configuration object to validate
* @param userRules - Optional user-defined validation rules
* @param useDefaultRules - Whether to use default validation rules
*/
validateConfigCompatibility(config, userRules, useDefaultRules = true) {
const warnings = this.validationService.validate(config, userRules, useDefaultRules);
warnings.forEach((warning) => this.logConfigWarning(warning));
}
/**
* Safely executes a configuration update operation and handles any errors
* @param operation - Function to execute
* @param errorMessage - Message to log if operation fails
* @returns The result of the operation or a fallback value if provided
*/
safeUpdate(operation, errorMessage, fallback) {
try {
return operation();
}
catch (e) {
this.logConfigWarning(`${errorMessage}: ${e.message}`);
return fallback;
}
}
checkDeprecatedCesiumConfig(newConfig) {
const deprecatedProps = [
'cesiumDebugShowFramesPerSecond',
'cesiumShadows',
'cesiumBase',
'createWorldTerrainOptions',
'terrain_provider',
'cesiumTimeline',
'cesiumAnimation',
'creditContainer',
'cesiumInfoBox',
'imageryProvider',
'terrainExaggeration',
'cesiumBingKey',
'newTerrainProviderOptions',
'terrain_providers',
'cesiumAccessToken',
'cesiumTime',
];
for (const prop of deprecatedProps) {
if (newConfig[prop] != undefined) {
console.error(`HsConfig.${prop} has been moved to HsCesiumConfig service or hslayersCesiumConfig.${prop} when using hslayers-cesium-app`);
}
}
}
update(newConfig) {
try {
if (!newConfig) {
this.logConfigWarning('Empty configuration provided');
return;
}
this.checkDeprecatedCesiumConfig(newConfig);
// Extract validation settings before processing
const userValidationRules = newConfig.configValidationRules;
const useDefaultRules = newConfig.useDefaultValidationRules ?? true;
if (newConfig.configValidationRules) {
delete newConfig.configValidationRules;
}
if (newConfig.useDefaultValidationRules !== undefined) {
delete newConfig.useDefaultValidationRules;
}
if (newConfig.sidebarPosition === 'bottom') {
/**Set high enough value to make sure class setting mobile-view is not toggled*/
newConfig.mobileBreakpoint = 9999;
}
// Update symbolizer icons with current assets path
this.safeUpdate(() => {
this.symbolizerIcons = this.defaultSymbolizerIcons.map((val) => ({
...val,
url: (this.assetsPath ?? '') + val.url,
}));
}, 'Error updating symbolizer icons');
// Update components enabled
this.componentsEnabled =
this.safeUpdate(() => this.updateComponentsEnabled(newConfig), 'Error updating components enabled', { ...this.componentsEnabled }) ?? this.componentsEnabled;
delete newConfig.componentsEnabled;
// Update panel widths
this.safeUpdate(() => Object.assign(this.panelWidths, newConfig.panelWidths ?? {}), 'Error updating panel widths');
delete newConfig.panelWidths;
// Update panels enabled
this.safeUpdate(() => Object.assign(this.panelsEnabled, newConfig.panelsEnabled ?? {}), 'Error updating panels enabled');
delete newConfig.panelsEnabled;
// Update symbolizer icons
this.symbolizerIcons =
this.safeUpdate(() => [
...this.updateSymbolizers(newConfig),
...(newConfig.symbolizerIcons ?? []),
], 'Error updating symbolizers', this.symbolizerIcons) ?? this.symbolizerIcons;
delete newConfig.symbolizerIcons;
// Merge remaining config
this.safeUpdate(() => Object.assign(this, newConfig), 'Error merging configuration');
// Handle assets path
if (this.assetsPath == undefined) {
this.assetsPath = '';
}
this.assetsPath += this.assetsPath.endsWith('/') ? '' : '/';
this.validateConfigCompatibility(this, userValidationRules, useDefaultRules);
this.configChanges.next();
}
catch (e) {
this.logConfigWarning('Critical error updating configuration: ' + e.message);
}
}
/**
* Merges componentsEnabled from newConfig with existing componentsEnabled
* Preserves the order of keys from newConfig.componentsEnabled
*/
updateComponentsEnabled(newConfig) {
if (!newConfig?.componentsEnabled) {
return { ...this.componentsEnabled };
}
try {
const orderedKeys = new Set([
...Object.keys(newConfig.componentsEnabled),
...Object.keys(this.componentsEnabled),
]);
const mergedComponentsEnabled = {};
orderedKeys.forEach((key) => {
mergedComponentsEnabled[key] =
newConfig.componentsEnabled[key] ?? this.componentsEnabled[key];
});
return mergedComponentsEnabled;
}
catch (e) {
this.logConfigWarning('Error in updateComponentsEnabled, using defaults: ' + e.message);
return { ...this.componentsEnabled };
}
}
updateSymbolizers(config) {
try {
let assetsPath = config.assetsPath ?? '';
assetsPath += assetsPath.endsWith('/') ? '' : '/';
return this.defaultSymbolizerIcons.map((val) => ({
...val,
url: assetsPath + val.url,
}));
}
catch (e) {
this.logConfigWarning('Error in updateSymbolizers: ' + e.message);
return [...this.defaultSymbolizerIcons];
}
}
setAppId(id) {
this.id = id;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfig, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfig, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.3", ngImport: i0, type: HsConfig, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { HsConfig, HsConfigObject, HsConfigValidationService };
//# sourceMappingURL=hslayers-ng-config.mjs.map