@open-pioneer/map 1.3.0-dev.20260225083007 → 1.3.0-dev.20260225104836
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/CHANGELOG.md +1 -1
- package/layers/WMSLayer.js +3 -6
- package/layers/WMSLayer.js.map +1 -1
- package/layers/WMTSLayer.js +1 -4
- package/layers/WMTSLayer.js.map +1 -1
- package/model/createMapModel.js +15 -0
- package/model/createMapModel.js.map +1 -1
- package/package.json +1 -1
- package/utils/sanitize.d.ts +0 -5
- package/utils/sanitize.js +1 -26
- package/utils/sanitize.js.map +1 -1
package/CHANGELOG.md
CHANGED
package/layers/WMSLayer.js
CHANGED
|
@@ -12,7 +12,6 @@ import { SublayersCollection } from './shared/SublayersCollection.js';
|
|
|
12
12
|
import { getAttributions } from './wms/getAttributions.js';
|
|
13
13
|
import { getLegendUrl } from './wms/getLegendUrl.js';
|
|
14
14
|
import { constructSublayers } from './wms/WMSSublayer.js';
|
|
15
|
-
import { sanitizeAttributions } from '../utils/sanitize.js';
|
|
16
15
|
|
|
17
16
|
const LOG = createLogger(sourceId);
|
|
18
17
|
const deprecatedConstructor = deprecated({
|
|
@@ -46,13 +45,11 @@ class WMSLayer extends AbstractLayer {
|
|
|
46
45
|
deps,
|
|
47
46
|
internalTag
|
|
48
47
|
);
|
|
49
|
-
const { attributions, ...sourceOptions } = config.sourceOptions ?? {};
|
|
50
48
|
const source = new ImageWMS({
|
|
51
|
-
|
|
52
|
-
...sourceOptions,
|
|
49
|
+
...config.sourceOptions,
|
|
53
50
|
url: config.url,
|
|
54
51
|
params: {
|
|
55
|
-
...sourceOptions?.params
|
|
52
|
+
...config.sourceOptions?.params
|
|
56
53
|
},
|
|
57
54
|
// Use http service to load tiles; needed for authentication etc.
|
|
58
55
|
imageLoadFunction: (wrapper, url) => {
|
|
@@ -179,7 +176,7 @@ class WMSLayer extends AbstractLayer {
|
|
|
179
176
|
if (this.#source.getAttributions() == null) {
|
|
180
177
|
const attributions = getAttributions(capabilities);
|
|
181
178
|
if (attributions) {
|
|
182
|
-
this.#source.setAttributions(
|
|
179
|
+
this.#source.setAttributions(attributions);
|
|
183
180
|
}
|
|
184
181
|
}
|
|
185
182
|
for (const layer of walkLeaves(this.#sublayers)) {
|
package/layers/WMSLayer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WMSLayer.js","sources":["WMSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch, computed, ReadonlyReactive, watch } from \"@conterra/reactivity-core\";\nimport {\n createLogger,\n deprecated,\n destroyResource,\n isAbortError,\n Resource\n} from \"@open-pioneer/core\";\nimport { ImageWrapper } from \"ol\";\nimport WMSCapabilities from \"ol/format/WMSCapabilities\";\nimport ImageLayer from \"ol/layer/Image\";\nimport type ImageSource from \"ol/source/Image\";\nimport type { Options as WMSSourceOptions } from \"ol/source/ImageWMS\";\nimport ImageWMS from \"ol/source/ImageWMS\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport type { LayerFactory } from \"../LayerFactory\";\nimport { MapModel } from \"../model/MapModel\";\nimport { fetchText } from \"../utils/fetch\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { AbstractLayer } from \"./AbstractLayer\";\nimport {\n ATTACH_TO_MAP,\n ATTACH_TO_PARENT,\n DETACH_FROM_MAP,\n GET_DEPS,\n GET_RAW_SUBLAYERS,\n LayerConstructor,\n LayerDependencies,\n SET_LEGEND\n} from \"./shared/internals\";\nimport { LayerConfig } from \"./shared/LayerConfig\";\nimport { SublayersCollection } from \"./shared/SublayersCollection\";\nimport { getAttributions } from \"./wms/getAttributions\";\nimport { getLegendUrl } from \"./wms/getLegendUrl\";\nimport { constructSublayers, WMSSublayer, WMSSublayerConfig } from \"./wms/WMSSublayer\";\nimport { sanitizeAttributions } from \"../utils/sanitize\";\nimport { Sublayer } from \"./unions\";\n\n/**\n * Configuration options to construct a {@link WMSLayer}.\n *\n * @group Layers\n */\nexport interface WMSLayerConfig extends LayerConfig {\n /** URL of the WMS service. */\n url: string;\n\n /** Configures the layer's sublayers. */\n sublayers?: WMSSublayerConfig[];\n\n /**\n * Additional source options for the layer's WMS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMS Layer manages some of the OpenLayers source options itself.\n */\n sourceOptions?: Partial<WMSSourceOptions>;\n\n /**\n * Whether to automatically fetch capabilities from the service when needed (default: `true`).\n *\n * Setting this to `false` can be useful as a performance optimization when capabilities are not really required by the application.\n * Note that this will disable some features of the WMS layer: for example, the legend URL will not be available.\n */\n fetchCapabilities?: boolean;\n}\n\nconst LOG = createLogger(sourceId);\n\nconst deprecatedConstructor = deprecated({\n name: \"WMSLayer constructor\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.0.0\",\n alternative: \"use LayerFactory.create() instead\"\n});\n\n/**\n * Displays an OGC Web Map Service (WMS).\n *\n * @group Layers\n */\nexport class WMSLayer extends AbstractLayer {\n #url: string;\n #sublayers: SublayersCollection<WMSSublayer>;\n #layer: ImageLayer<ImageSource>;\n #source: ImageWMS;\n #fetchCapabilities: boolean;\n\n #loadStarted = false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #capabilities: Record<string, any> | undefined;\n readonly #abortController = new AbortController();\n\n #visibleSublayers: ReadonlyReactive<string[]>;\n #sublayersWatch: Resource | undefined;\n\n /**\n * @deprecated Prefer using {@link LayerFactory.create} instead of calling the constructor directly\n */\n constructor(config: WMSLayerConfig);\n\n /**\n * NOTE: Do not use this overload. Use {@link LayerFactory.create} instead.\n *\n * @internal\n */\n constructor(\n config: WMSLayerConfig,\n deps: LayerDependencies,\n internalTag: InternalConstructorTag\n );\n constructor(\n config: WMSLayerConfig,\n deps?: LayerDependencies,\n internalTag?: InternalConstructorTag\n ) {\n if (!internalTag) {\n deprecatedConstructor();\n }\n\n const layer = new ImageLayer();\n super(\n {\n ...config,\n olLayer: layer\n },\n deps,\n internalTag\n );\n const { attributions, ...sourceOptions } = config.sourceOptions ?? {};\n const source = new ImageWMS({\n attributions: sanitizeAttributions(attributions),\n ...sourceOptions,\n url: config.url,\n params: {\n ...sourceOptions?.params\n },\n // Use http service to load tiles; needed for authentication etc.\n imageLoadFunction: (wrapper, url) => {\n return this.#loadImage(wrapper, url).catch((error) => {\n LOG.error(`Failed to load tile at '${url}'`, error);\n });\n }\n });\n this.#url = config.url;\n this.#fetchCapabilities = config.fetchCapabilities ?? true;\n this.#source = source;\n this.#layer = layer;\n\n this.#sublayers = new SublayersCollection(\n constructSublayers(config.sublayers),\n INTERNAL_CONSTRUCTOR_TAG\n );\n this.#sublayers\n [GET_RAW_SUBLAYERS]()\n .forEach((sublayer) => sublayer[ATTACH_TO_PARENT](this, this));\n\n this.#visibleSublayers = computed(() => this.#getVisibleLayerNames(), {\n equal(a, b) {\n return a.length === b.length && a.every((v, i) => v === b[i]);\n }\n });\n\n this.#sublayersWatch = watch(\n () => [this.#visibleSublayers.value],\n ([layers]) => {\n this.#updateLayersParam(layers);\n },\n {\n immediate: true\n }\n );\n }\n\n override destroy() {\n this.#abortController.abort();\n this.#sublayersWatch = destroyResource(this.#sublayersWatch);\n super.destroy();\n }\n\n get type() {\n return \"wms\" as const;\n }\n\n get legend() {\n return undefined;\n }\n\n /** The URL of the WMS service that was used during layer construction. */\n get url(): string {\n return this.#url;\n }\n\n get layers(): undefined {\n return undefined;\n }\n\n /**\n * Holds the sublayers of this layer.\n */\n get sublayers(): SublayersCollection<WMSSublayer> {\n return this.#sublayers;\n }\n\n get capabilities() {\n return this.#capabilities;\n }\n\n /** @internal */\n [ATTACH_TO_MAP](map: MapModel): void {\n super[ATTACH_TO_MAP](map);\n for (const sublayer of this.#sublayers.getSublayers()) {\n sublayer[ATTACH_TO_MAP](map);\n }\n\n this.#load();\n }\n\n /** @internal */\n [DETACH_FROM_MAP](): void {\n super[DETACH_FROM_MAP]();\n for (const sublayer of this.#sublayers.getSublayers()) {\n sublayer[DETACH_FROM_MAP]();\n }\n }\n\n #load() {\n if (this.#loadStarted || !this.#fetchCapabilities) {\n return;\n }\n this.#loadStarted = true;\n this.#fetchWMSCapabilities()\n .then((result: string) => {\n batch(() => {\n this.#initializeWithMetadata(result);\n });\n })\n .catch((error) => {\n if (isAbortError(error)) {\n LOG.debug(`Layer '${this.id}' has been destroyed before fetching capabilities`);\n return;\n }\n LOG.error(`Failed to initialize WMS layer '${this.id}'`, error);\n });\n }\n\n /**\n * Gathers the visibility of _all_ sublayers and assembles the 'layers' WMS parameter.\n * The parameters are then applied to the WMS source.\n */\n #updateLayersParam(layers: string[]) {\n this.#source.updateParams({\n \"LAYERS\": layers\n });\n\n // only set source if there are visible sublayers, otherwise\n // we send an invalid http request\n const source = layers.length === 0 ? null : this.#source;\n if (this.#layer.getSource() !== source) {\n this.#layer.setSource(source);\n }\n }\n\n #getVisibleLayerNames() {\n const layers: string[] = [];\n const filter = (sublayer: Sublayer) => sublayer.visible;\n for (const sublayer of walkLeaves(this.#sublayers, filter)) {\n // Push sublayer if layer name is not an empty string | undefined | ...\n if (sublayer.name) {\n layers.push(sublayer.name);\n }\n }\n return layers;\n }\n\n async #fetchWMSCapabilities(): Promise<string> {\n const httpService = this[GET_DEPS]().httpService;\n const url = `${this.#url}?LANGUAGE=ger&SERVICE=WMS&REQUEST=GetCapabilities`;\n return fetchText(url, httpService, this.#abortController.signal);\n }\n\n #initializeWithMetadata(metadata: string) {\n const parser = new WMSCapabilities();\n const capabilities = parser.read(metadata);\n this.#capabilities = capabilities;\n\n // Apply attributions from metadata if none are set.\n if (this.#source.getAttributions() == null) {\n const attributions = getAttributions(capabilities);\n if (attributions) {\n this.#source.setAttributions(sanitizeAttributions(attributions));\n }\n }\n\n for (const layer of walkLeaves(this.#sublayers)) {\n if (layer.name) {\n const legendUrl = getLegendUrl(capabilities, layer.name);\n layer[SET_LEGEND](legendUrl);\n }\n }\n }\n\n async #loadImage(imageWrapper: ImageWrapper, imageUrl: string): Promise<void> {\n const httpService = this[GET_DEPS]().httpService;\n const image = imageWrapper.getImage() as HTMLImageElement;\n\n const response = await httpService.fetch(imageUrl);\n if (!response.ok) {\n throw new Error(`Request failed with status ${response.status}.`);\n }\n\n const blob = await response.blob();\n const objectUrl = URL.createObjectURL(blob);\n const finish = () => {\n // Cleanup object URL after load to prevent memory leaks.\n // https://stackoverflow.com/questions/62473876/openlayers-6-settileloadfunction-documented-example-uses-url-createobjecturld\n URL.revokeObjectURL(objectUrl);\n image.removeEventListener(\"load\", finish);\n image.removeEventListener(\"error\", finish);\n };\n\n image.addEventListener(\"load\", finish);\n image.addEventListener(\"error\", finish);\n image.src = objectUrl;\n }\n}\n\n/**\n * Yields all leaf notes in the given collection (recursively).\n */\nfunction* walkLeaves(\n sublayers: SublayersCollection<WMSSublayer>,\n filter?: (sublayer: Sublayer) => boolean\n): Generator<WMSSublayer> {\n for (const sublayer of sublayers[GET_RAW_SUBLAYERS]()) {\n if (filter && !filter(sublayer)) {\n continue;\n }\n\n const nested = sublayer.sublayers[GET_RAW_SUBLAYERS]();\n if (nested.length) {\n yield* walkLeaves(sublayer.sublayers, filter);\n } else {\n yield sublayer;\n }\n }\n}\n\n// Ensure layer class is assignable to the constructor interface (there is no \"implements\" for the class itself).\n// eslint-disable-next-line no-constant-condition\nif (false) {\n const check: LayerConstructor<WMSLayerConfig, WMSLayer> = WMSLayer;\n void check;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WMSLayer.js","sources":["WMSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch, computed, ReadonlyReactive, watch } from \"@conterra/reactivity-core\";\nimport {\n createLogger,\n deprecated,\n destroyResource,\n isAbortError,\n Resource\n} from \"@open-pioneer/core\";\nimport { ImageWrapper } from \"ol\";\nimport WMSCapabilities from \"ol/format/WMSCapabilities\";\nimport ImageLayer from \"ol/layer/Image\";\nimport type ImageSource from \"ol/source/Image\";\nimport type { Options as WMSSourceOptions } from \"ol/source/ImageWMS\";\nimport ImageWMS from \"ol/source/ImageWMS\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport type { LayerFactory } from \"../LayerFactory\";\nimport { MapModel } from \"../model/MapModel\";\nimport { fetchText } from \"../utils/fetch\";\nimport { INTERNAL_CONSTRUCTOR_TAG, InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { AbstractLayer } from \"./AbstractLayer\";\nimport {\n ATTACH_TO_MAP,\n ATTACH_TO_PARENT,\n DETACH_FROM_MAP,\n GET_DEPS,\n GET_RAW_SUBLAYERS,\n LayerConstructor,\n LayerDependencies,\n SET_LEGEND\n} from \"./shared/internals\";\nimport { LayerConfig } from \"./shared/LayerConfig\";\nimport { SublayersCollection } from \"./shared/SublayersCollection\";\nimport { getAttributions } from \"./wms/getAttributions\";\nimport { getLegendUrl } from \"./wms/getLegendUrl\";\nimport { constructSublayers, WMSSublayer, WMSSublayerConfig } from \"./wms/WMSSublayer\";\nimport { Sublayer } from \"./unions\";\n\n/**\n * Configuration options to construct a {@link WMSLayer}.\n *\n * @group Layers\n */\nexport interface WMSLayerConfig extends LayerConfig {\n /** URL of the WMS service. */\n url: string;\n\n /** Configures the layer's sublayers. */\n sublayers?: WMSSublayerConfig[];\n\n /**\n * Additional source options for the layer's WMS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMS Layer manages some of the OpenLayers source options itself.\n */\n sourceOptions?: Partial<WMSSourceOptions>;\n\n /**\n * Whether to automatically fetch capabilities from the service when needed (default: `true`).\n *\n * Setting this to `false` can be useful as a performance optimization when capabilities are not really required by the application.\n * Note that this will disable some features of the WMS layer: for example, the legend URL will not be available.\n */\n fetchCapabilities?: boolean;\n}\n\nconst LOG = createLogger(sourceId);\n\nconst deprecatedConstructor = deprecated({\n name: \"WMSLayer constructor\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.0.0\",\n alternative: \"use LayerFactory.create() instead\"\n});\n\n/**\n * Displays an OGC Web Map Service (WMS).\n *\n * @group Layers\n */\nexport class WMSLayer extends AbstractLayer {\n #url: string;\n #sublayers: SublayersCollection<WMSSublayer>;\n #layer: ImageLayer<ImageSource>;\n #source: ImageWMS;\n #fetchCapabilities: boolean;\n\n #loadStarted = false;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #capabilities: Record<string, any> | undefined;\n readonly #abortController = new AbortController();\n\n #visibleSublayers: ReadonlyReactive<string[]>;\n #sublayersWatch: Resource | undefined;\n\n /**\n * @deprecated Prefer using {@link LayerFactory.create} instead of calling the constructor directly\n */\n constructor(config: WMSLayerConfig);\n\n /**\n * NOTE: Do not use this overload. Use {@link LayerFactory.create} instead.\n *\n * @internal\n */\n constructor(\n config: WMSLayerConfig,\n deps: LayerDependencies,\n internalTag: InternalConstructorTag\n );\n constructor(\n config: WMSLayerConfig,\n deps?: LayerDependencies,\n internalTag?: InternalConstructorTag\n ) {\n if (!internalTag) {\n deprecatedConstructor();\n }\n\n const layer = new ImageLayer();\n super(\n {\n ...config,\n olLayer: layer\n },\n deps,\n internalTag\n );\n const source = new ImageWMS({\n ...config.sourceOptions,\n url: config.url,\n params: {\n ...config.sourceOptions?.params\n },\n // Use http service to load tiles; needed for authentication etc.\n imageLoadFunction: (wrapper, url) => {\n return this.#loadImage(wrapper, url).catch((error) => {\n LOG.error(`Failed to load tile at '${url}'`, error);\n });\n }\n });\n this.#url = config.url;\n this.#fetchCapabilities = config.fetchCapabilities ?? true;\n this.#source = source;\n this.#layer = layer;\n\n this.#sublayers = new SublayersCollection(\n constructSublayers(config.sublayers),\n INTERNAL_CONSTRUCTOR_TAG\n );\n this.#sublayers\n [GET_RAW_SUBLAYERS]()\n .forEach((sublayer) => sublayer[ATTACH_TO_PARENT](this, this));\n\n this.#visibleSublayers = computed(() => this.#getVisibleLayerNames(), {\n equal(a, b) {\n return a.length === b.length && a.every((v, i) => v === b[i]);\n }\n });\n\n this.#sublayersWatch = watch(\n () => [this.#visibleSublayers.value],\n ([layers]) => {\n this.#updateLayersParam(layers);\n },\n {\n immediate: true\n }\n );\n }\n\n override destroy() {\n this.#abortController.abort();\n this.#sublayersWatch = destroyResource(this.#sublayersWatch);\n super.destroy();\n }\n\n get type() {\n return \"wms\" as const;\n }\n\n get legend() {\n return undefined;\n }\n\n /** The URL of the WMS service that was used during layer construction. */\n get url(): string {\n return this.#url;\n }\n\n get layers(): undefined {\n return undefined;\n }\n\n /**\n * Holds the sublayers of this layer.\n */\n get sublayers(): SublayersCollection<WMSSublayer> {\n return this.#sublayers;\n }\n\n get capabilities() {\n return this.#capabilities;\n }\n\n /** @internal */\n [ATTACH_TO_MAP](map: MapModel): void {\n super[ATTACH_TO_MAP](map);\n for (const sublayer of this.#sublayers.getSublayers()) {\n sublayer[ATTACH_TO_MAP](map);\n }\n\n this.#load();\n }\n\n /** @internal */\n [DETACH_FROM_MAP](): void {\n super[DETACH_FROM_MAP]();\n for (const sublayer of this.#sublayers.getSublayers()) {\n sublayer[DETACH_FROM_MAP]();\n }\n }\n\n #load() {\n if (this.#loadStarted || !this.#fetchCapabilities) {\n return;\n }\n this.#loadStarted = true;\n this.#fetchWMSCapabilities()\n .then((result: string) => {\n batch(() => {\n this.#initializeWithMetadata(result);\n });\n })\n .catch((error) => {\n if (isAbortError(error)) {\n LOG.debug(`Layer '${this.id}' has been destroyed before fetching capabilities`);\n return;\n }\n LOG.error(`Failed to initialize WMS layer '${this.id}'`, error);\n });\n }\n\n /**\n * Gathers the visibility of _all_ sublayers and assembles the 'layers' WMS parameter.\n * The parameters are then applied to the WMS source.\n */\n #updateLayersParam(layers: string[]) {\n this.#source.updateParams({\n \"LAYERS\": layers\n });\n\n // only set source if there are visible sublayers, otherwise\n // we send an invalid http request\n const source = layers.length === 0 ? null : this.#source;\n if (this.#layer.getSource() !== source) {\n this.#layer.setSource(source);\n }\n }\n\n #getVisibleLayerNames() {\n const layers: string[] = [];\n const filter = (sublayer: Sublayer) => sublayer.visible;\n for (const sublayer of walkLeaves(this.#sublayers, filter)) {\n // Push sublayer if layer name is not an empty string | undefined | ...\n if (sublayer.name) {\n layers.push(sublayer.name);\n }\n }\n return layers;\n }\n\n async #fetchWMSCapabilities(): Promise<string> {\n const httpService = this[GET_DEPS]().httpService;\n const url = `${this.#url}?LANGUAGE=ger&SERVICE=WMS&REQUEST=GetCapabilities`;\n return fetchText(url, httpService, this.#abortController.signal);\n }\n\n #initializeWithMetadata(metadata: string) {\n const parser = new WMSCapabilities();\n const capabilities = parser.read(metadata);\n this.#capabilities = capabilities;\n\n // Apply attributions from metadata if none are set.\n if (this.#source.getAttributions() == null) {\n const attributions = getAttributions(capabilities);\n if (attributions) {\n this.#source.setAttributions(attributions);\n }\n }\n\n for (const layer of walkLeaves(this.#sublayers)) {\n if (layer.name) {\n const legendUrl = getLegendUrl(capabilities, layer.name);\n layer[SET_LEGEND](legendUrl);\n }\n }\n }\n\n async #loadImage(imageWrapper: ImageWrapper, imageUrl: string): Promise<void> {\n const httpService = this[GET_DEPS]().httpService;\n const image = imageWrapper.getImage() as HTMLImageElement;\n\n const response = await httpService.fetch(imageUrl);\n if (!response.ok) {\n throw new Error(`Request failed with status ${response.status}.`);\n }\n\n const blob = await response.blob();\n const objectUrl = URL.createObjectURL(blob);\n const finish = () => {\n // Cleanup object URL after load to prevent memory leaks.\n // https://stackoverflow.com/questions/62473876/openlayers-6-settileloadfunction-documented-example-uses-url-createobjecturld\n URL.revokeObjectURL(objectUrl);\n image.removeEventListener(\"load\", finish);\n image.removeEventListener(\"error\", finish);\n };\n\n image.addEventListener(\"load\", finish);\n image.addEventListener(\"error\", finish);\n image.src = objectUrl;\n }\n}\n\n/**\n * Yields all leaf notes in the given collection (recursively).\n */\nfunction* walkLeaves(\n sublayers: SublayersCollection<WMSSublayer>,\n filter?: (sublayer: Sublayer) => boolean\n): Generator<WMSSublayer> {\n for (const sublayer of sublayers[GET_RAW_SUBLAYERS]()) {\n if (filter && !filter(sublayer)) {\n continue;\n }\n\n const nested = sublayer.sublayers[GET_RAW_SUBLAYERS]();\n if (nested.length) {\n yield* walkLeaves(sublayer.sublayers, filter);\n } else {\n yield sublayer;\n }\n }\n}\n\n// Ensure layer class is assignable to the constructor interface (there is no \"implements\" for the class itself).\n// eslint-disable-next-line no-constant-condition\nif (false) {\n const check: LayerConstructor<WMSLayerConfig, WMSLayer> = WMSLayer;\n void check;\n}\n"],"names":[],"mappings":"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"}
|
package/layers/WMTSLayer.js
CHANGED
|
@@ -7,7 +7,6 @@ import TileLayer from 'ol/layer/Tile.js';
|
|
|
7
7
|
import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS.js';
|
|
8
8
|
import { sourceId$3 as sourceId } from '../_virtual/source-info.js';
|
|
9
9
|
import { fetchText } from '../utils/fetch.js';
|
|
10
|
-
import { sanitizeAttributions } from '../utils/sanitize.js';
|
|
11
10
|
import { AbstractLayer } from './AbstractLayer.js';
|
|
12
11
|
import { ATTACH_TO_MAP, GET_DEPS } from './shared/internals.js';
|
|
13
12
|
import { getAttributions } from './wmts/getAttributions.js';
|
|
@@ -121,9 +120,7 @@ class WMTSLayer extends AbstractLayer {
|
|
|
121
120
|
throw new Error(`Style '${sourceOptions.style}' was not found in capabilities`);
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
|
-
const attributions =
|
|
125
|
-
explicitAttributions ?? getAttributions(capabilities)
|
|
126
|
-
);
|
|
123
|
+
const attributions = explicitAttributions ?? getAttributions(capabilities);
|
|
127
124
|
const source = new WMTS({
|
|
128
125
|
...options,
|
|
129
126
|
attributions,
|
package/layers/WMTSLayer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WMTSLayer.js","sources":["WMTSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch, reactive } from \"@conterra/reactivity-core\";\nimport { createLogger, deprecated, isAbortError } from \"@open-pioneer/core\";\nimport { ImageTile } from \"ol\";\nimport Tile from \"ol/Tile\";\nimport TileState from \"ol/TileState\";\nimport WMTSCapabilities from \"ol/format/WMTSCapabilities\";\nimport TileLayer from \"ol/layer/Tile\";\nimport type TileSourceType from \"ol/source/Tile\";\nimport WMTS, { optionsFromCapabilities, Options as WMTSSourceOptions } from \"ol/source/WMTS\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport type { LayerFactory } from \"../LayerFactory\";\nimport { MapModel } from \"../model/MapModel\";\nimport { InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { fetchText } from \"../utils/fetch\";\nimport { sanitizeAttributions } from \"../utils/sanitize\";\nimport { AbstractLayer } from \"./AbstractLayer\";\nimport { LayerConfig } from \"./shared/LayerConfig\";\nimport { ATTACH_TO_MAP, GET_DEPS, LayerConstructor, LayerDependencies } from \"./shared/internals\";\nimport { getAttributions } from \"./wmts/getAttributions\";\nimport { getLegendUrl } from \"./wmts/getLegendUrl\";\n\n/**\n * Configuration options supported by {@link WMTSLayer}.\n *\n * @group Layers\n */\nexport interface WMTSLayerConfig extends LayerConfig {\n /** URL of the WMTS service. */\n url: string;\n\n /** The name of the WMTS layer in the service's capabilities. */\n name: string;\n\n /** The name of the tile matrix set in the service's capabilities. */\n matrixSet: string;\n\n /**\n * Additional source options for the layer's WMTS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMTS Layer manages some of the OpenLayers source options itself.\n */\n sourceOptions?: Partial<WMTSSourceOptions>;\n}\n\nconst LOG = createLogger(sourceId);\n\nconst deprecatedConstructor = deprecated({\n name: \"WMTSLayer constructor\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.0.0\",\n alternative: \"use LayerFactory.create() instead\"\n});\n\n/**\n * Displays an OGC Web Map Tile Service (WMTS).\n *\n * @group Layers\n */\nexport class WMTSLayer extends AbstractLayer {\n #url: string;\n #name: string;\n #matrixSet: string;\n #layer: TileLayer<TileSourceType>;\n #sourceOptions: Partial<WMTSSourceOptions>;\n #legend = reactive<string | undefined>();\n\n #loadStarted = false;\n\n readonly #abortController = new AbortController();\n\n /**\n * @deprecated Prefer using {@link LayerFactory.create} instead of calling the constructor directly\n */\n constructor(config: WMTSLayerConfig);\n\n /**\n * NOTE: Do not use this overload. Use {@link LayerFactory.create} instead.\n *\n * @internal\n */\n constructor(\n config: WMTSLayerConfig,\n deps: LayerDependencies,\n internalTag: InternalConstructorTag\n );\n\n constructor(\n config: WMTSLayerConfig,\n deps?: LayerDependencies,\n internalTag?: InternalConstructorTag\n ) {\n if (!internalTag) {\n deprecatedConstructor();\n }\n\n const layer = new TileLayer();\n super(\n {\n ...config,\n olLayer: layer\n },\n deps,\n internalTag\n );\n this.#url = config.url;\n this.#name = config.name;\n this.#layer = layer;\n this.#matrixSet = config.matrixSet;\n this.#sourceOptions = config.sourceOptions ?? {};\n }\n\n destroy(): void {\n this.#abortController.abort();\n super.destroy();\n }\n\n get type() {\n return \"wmts\" as const;\n }\n\n /** URL of the WMTS service. */\n override get legend(): string | undefined {\n return this.#legend.value;\n }\n\n override get sublayers(): undefined {\n return undefined;\n }\n\n override get layers(): undefined {\n return undefined;\n }\n\n get url() {\n return this.#url;\n }\n\n /** The name of the WMTS layer in the service's capabilities. */\n get name() {\n return this.#name;\n }\n\n /** The name of the tile matrix set in the service's capabilities. */\n get matrixSet() {\n return this.#matrixSet;\n }\n\n override [ATTACH_TO_MAP](map: MapModel): void {\n super[ATTACH_TO_MAP](map);\n this.#load();\n }\n\n #load() {\n if (this.#loadStarted) {\n return;\n }\n this.#loadStarted = true;\n this.#fetchWMTSCapabilities()\n .then((result: string) => {\n batch(() => {\n this.#initializeWithMetadata(result);\n });\n })\n .catch((error) => {\n if (isAbortError(error)) {\n LOG.debug(`Layer '${this.name}' has been destroyed before fetching the data`);\n return;\n }\n LOG.error(`Failed to initialize WMTS layer '${this.name}'`, error);\n //TODO: how to set the load state to error?\n });\n }\n\n async #fetchWMTSCapabilities(): Promise<string> {\n const httpService = this[GET_DEPS]().httpService;\n return fetchText(this.#url, httpService, this.#abortController.signal);\n }\n\n #initializeWithMetadata(metadata: string) {\n const parser = new WMTSCapabilities();\n const capabilities = parser.read(metadata);\n const options = optionsFromCapabilities(capabilities, {\n layer: this.#name,\n matrixSet: this.#matrixSet\n });\n if (!options) {\n throw new Error(`Layer '${this.#name}' was not found in capabilities`);\n }\n if (options.matrixSet !== this.#matrixSet) {\n throw new Error(`Tile matrix set '${this.#matrixSet}' was not found in capabilities`);\n }\n\n const { attributions: explicitAttributions, ...sourceOptions } = this.#sourceOptions;\n if (sourceOptions.style && sourceOptions.style !== options.style) {\n const styleToUse = this.#existsStyleInCapabilities(capabilities, sourceOptions.style);\n if (!styleToUse) {\n throw new Error(`Style '${sourceOptions.style}' was not found in capabilities`);\n }\n }\n\n const attributions = sanitizeAttributions(\n explicitAttributions ?? getAttributions(capabilities)\n );\n const source = new WMTS({\n ...options,\n attributions,\n ...sourceOptions,\n tileLoadFunction: (tile, tileUrl) => {\n this.#loadTile(tile, tileUrl);\n }\n });\n this.#layer.setSource(source);\n\n const activeStyleId = source.getStyle();\n const legendUrl = getLegendUrl(capabilities, this.name, activeStyleId);\n this.#legend.value = legendUrl;\n }\n\n async #loadTile(tile: Tile, tileUrl: string): Promise<void> {\n const httpService = this[GET_DEPS]().httpService;\n try {\n if (!(tile instanceof ImageTile)) {\n throw new Error(\"Only 'ImageTile' is supported for now.\");\n }\n\n const image = tile.getImage();\n if (!isHtmlImage(image)) {\n // Could also be canvas or video\n throw new Error(\"Only <img> tags are supported as tiles for now.\");\n }\n\n const response = await httpService.fetch(tileUrl);\n if (!response.ok) {\n throw new Error(`Tile request failed with status ${response.status}.`);\n }\n\n const blob = await response.blob();\n const objectUrl = URL.createObjectURL(blob);\n const finish = () => {\n // Cleanup object URL after load to prevent memory leaks.\n // https://stackoverflow.com/questions/62473876/openlayers-6-settileloadfunction-documented-example-uses-url-createobjecturld\n URL.revokeObjectURL(objectUrl);\n image.removeEventListener(\"load\", finish);\n image.removeEventListener(\"error\", finish);\n };\n image.addEventListener(\"load\", finish);\n image.addEventListener(\"error\", finish);\n image.src = objectUrl;\n } catch (e) {\n tile.setState(TileState.ERROR);\n if (!isAbortError(e)) {\n LOG.error(\"Failed to load tile\", e);\n }\n }\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n #existsStyleInCapabilities(capabilities: any, styleToUse: string): boolean {\n // NOTE: we have a style override, check if the style exists in the capabilities\n // the helper optionsFromCapabilities, supports style, too, but uses the Title instead of the Identifier, to find a match in the capabilities\n const layerDesc = capabilities.Contents?.Layer?.find(\n (layer: any) => layer.Identifier === this.#name\n );\n return layerDesc?.Style?.some((style: any) => style.Identifier === styleToUse) ?? false;\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n\n// Ensure layer class is assignable to the constructor interface (there is no \"implements\" for the class itself).\n// eslint-disable-next-line no-constant-condition\nif (false) {\n const check: LayerConstructor<WMTSLayerConfig, WMTSLayer> = WMTSLayer;\n void check;\n}\n\nfunction isHtmlImage(htmlElement: HTMLElement | OffscreenCanvas): htmlElement is HTMLImageElement {\n return \"tagName\" in htmlElement && htmlElement.tagName === \"IMG\";\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WMTSLayer.js","sources":["WMTSLayer.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch, reactive } from \"@conterra/reactivity-core\";\nimport { createLogger, deprecated, isAbortError } from \"@open-pioneer/core\";\nimport { ImageTile } from \"ol\";\nimport Tile from \"ol/Tile\";\nimport TileState from \"ol/TileState\";\nimport WMTSCapabilities from \"ol/format/WMTSCapabilities\";\nimport TileLayer from \"ol/layer/Tile\";\nimport type TileSourceType from \"ol/source/Tile\";\nimport WMTS, { optionsFromCapabilities, Options as WMTSSourceOptions } from \"ol/source/WMTS\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport type { LayerFactory } from \"../LayerFactory\";\nimport { MapModel } from \"../model/MapModel\";\nimport { InternalConstructorTag } from \"../utils/InternalConstructorTag\";\nimport { fetchText } from \"../utils/fetch\";\nimport { AbstractLayer } from \"./AbstractLayer\";\nimport { LayerConfig } from \"./shared/LayerConfig\";\nimport { ATTACH_TO_MAP, GET_DEPS, LayerConstructor, LayerDependencies } from \"./shared/internals\";\nimport { getAttributions } from \"./wmts/getAttributions\";\nimport { getLegendUrl } from \"./wmts/getLegendUrl\";\n\n/**\n * Configuration options supported by {@link WMTSLayer}.\n *\n * @group Layers\n */\nexport interface WMTSLayerConfig extends LayerConfig {\n /** URL of the WMTS service. */\n url: string;\n\n /** The name of the WMTS layer in the service's capabilities. */\n name: string;\n\n /** The name of the tile matrix set in the service's capabilities. */\n matrixSet: string;\n\n /**\n * Additional source options for the layer's WMTS source.\n *\n * NOTE: These options are intended for advanced configuration:\n * the WMTS Layer manages some of the OpenLayers source options itself.\n */\n sourceOptions?: Partial<WMTSSourceOptions>;\n}\n\nconst LOG = createLogger(sourceId);\n\nconst deprecatedConstructor = deprecated({\n name: \"WMTSLayer constructor\",\n packageName: \"@open-pioneer/map\",\n since: \"v1.0.0\",\n alternative: \"use LayerFactory.create() instead\"\n});\n\n/**\n * Displays an OGC Web Map Tile Service (WMTS).\n *\n * @group Layers\n */\nexport class WMTSLayer extends AbstractLayer {\n #url: string;\n #name: string;\n #matrixSet: string;\n #layer: TileLayer<TileSourceType>;\n #sourceOptions: Partial<WMTSSourceOptions>;\n #legend = reactive<string | undefined>();\n\n #loadStarted = false;\n\n readonly #abortController = new AbortController();\n\n /**\n * @deprecated Prefer using {@link LayerFactory.create} instead of calling the constructor directly\n */\n constructor(config: WMTSLayerConfig);\n\n /**\n * NOTE: Do not use this overload. Use {@link LayerFactory.create} instead.\n *\n * @internal\n */\n constructor(\n config: WMTSLayerConfig,\n deps: LayerDependencies,\n internalTag: InternalConstructorTag\n );\n\n constructor(\n config: WMTSLayerConfig,\n deps?: LayerDependencies,\n internalTag?: InternalConstructorTag\n ) {\n if (!internalTag) {\n deprecatedConstructor();\n }\n\n const layer = new TileLayer();\n super(\n {\n ...config,\n olLayer: layer\n },\n deps,\n internalTag\n );\n this.#url = config.url;\n this.#name = config.name;\n this.#layer = layer;\n this.#matrixSet = config.matrixSet;\n this.#sourceOptions = config.sourceOptions ?? {};\n }\n\n destroy(): void {\n this.#abortController.abort();\n super.destroy();\n }\n\n get type() {\n return \"wmts\" as const;\n }\n\n /** URL of the WMTS service. */\n override get legend(): string | undefined {\n return this.#legend.value;\n }\n\n override get sublayers(): undefined {\n return undefined;\n }\n\n override get layers(): undefined {\n return undefined;\n }\n\n get url() {\n return this.#url;\n }\n\n /** The name of the WMTS layer in the service's capabilities. */\n get name() {\n return this.#name;\n }\n\n /** The name of the tile matrix set in the service's capabilities. */\n get matrixSet() {\n return this.#matrixSet;\n }\n\n override [ATTACH_TO_MAP](map: MapModel): void {\n super[ATTACH_TO_MAP](map);\n this.#load();\n }\n\n #load() {\n if (this.#loadStarted) {\n return;\n }\n this.#loadStarted = true;\n this.#fetchWMTSCapabilities()\n .then((result: string) => {\n batch(() => {\n this.#initializeWithMetadata(result);\n });\n })\n .catch((error) => {\n if (isAbortError(error)) {\n LOG.debug(`Layer '${this.name}' has been destroyed before fetching the data`);\n return;\n }\n LOG.error(`Failed to initialize WMTS layer '${this.name}'`, error);\n //TODO: how to set the load state to error?\n });\n }\n\n async #fetchWMTSCapabilities(): Promise<string> {\n const httpService = this[GET_DEPS]().httpService;\n return fetchText(this.#url, httpService, this.#abortController.signal);\n }\n\n #initializeWithMetadata(metadata: string) {\n const parser = new WMTSCapabilities();\n const capabilities = parser.read(metadata);\n const options = optionsFromCapabilities(capabilities, {\n layer: this.#name,\n matrixSet: this.#matrixSet\n });\n if (!options) {\n throw new Error(`Layer '${this.#name}' was not found in capabilities`);\n }\n if (options.matrixSet !== this.#matrixSet) {\n throw new Error(`Tile matrix set '${this.#matrixSet}' was not found in capabilities`);\n }\n\n const { attributions: explicitAttributions, ...sourceOptions } = this.#sourceOptions;\n if (sourceOptions.style && sourceOptions.style !== options.style) {\n const styleToUse = this.#existsStyleInCapabilities(capabilities, sourceOptions.style);\n if (!styleToUse) {\n throw new Error(`Style '${sourceOptions.style}' was not found in capabilities`);\n }\n }\n\n const attributions = explicitAttributions ?? getAttributions(capabilities);\n const source = new WMTS({\n ...options,\n attributions,\n ...sourceOptions,\n tileLoadFunction: (tile, tileUrl) => {\n this.#loadTile(tile, tileUrl);\n }\n });\n this.#layer.setSource(source);\n\n const activeStyleId = source.getStyle();\n const legendUrl = getLegendUrl(capabilities, this.name, activeStyleId);\n this.#legend.value = legendUrl;\n }\n\n async #loadTile(tile: Tile, tileUrl: string): Promise<void> {\n const httpService = this[GET_DEPS]().httpService;\n try {\n if (!(tile instanceof ImageTile)) {\n throw new Error(\"Only 'ImageTile' is supported for now.\");\n }\n\n const image = tile.getImage();\n if (!isHtmlImage(image)) {\n // Could also be canvas or video\n throw new Error(\"Only <img> tags are supported as tiles for now.\");\n }\n\n const response = await httpService.fetch(tileUrl);\n if (!response.ok) {\n throw new Error(`Tile request failed with status ${response.status}.`);\n }\n\n const blob = await response.blob();\n const objectUrl = URL.createObjectURL(blob);\n const finish = () => {\n // Cleanup object URL after load to prevent memory leaks.\n // https://stackoverflow.com/questions/62473876/openlayers-6-settileloadfunction-documented-example-uses-url-createobjecturld\n URL.revokeObjectURL(objectUrl);\n image.removeEventListener(\"load\", finish);\n image.removeEventListener(\"error\", finish);\n };\n image.addEventListener(\"load\", finish);\n image.addEventListener(\"error\", finish);\n image.src = objectUrl;\n } catch (e) {\n tile.setState(TileState.ERROR);\n if (!isAbortError(e)) {\n LOG.error(\"Failed to load tile\", e);\n }\n }\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n #existsStyleInCapabilities(capabilities: any, styleToUse: string): boolean {\n // NOTE: we have a style override, check if the style exists in the capabilities\n // the helper optionsFromCapabilities, supports style, too, but uses the Title instead of the Identifier, to find a match in the capabilities\n const layerDesc = capabilities.Contents?.Layer?.find(\n (layer: any) => layer.Identifier === this.#name\n );\n return layerDesc?.Style?.some((style: any) => style.Identifier === styleToUse) ?? false;\n }\n /* eslint-enable @typescript-eslint/no-explicit-any */\n}\n\n// Ensure layer class is assignable to the constructor interface (there is no \"implements\" for the class itself).\n// eslint-disable-next-line no-constant-condition\nif (false) {\n const check: LayerConstructor<WMTSLayerConfig, WMTSLayer> = WMTSLayer;\n void check;\n}\n\nfunction isHtmlImage(htmlElement: HTMLElement | OffscreenCanvas): htmlElement is HTMLImageElement {\n return \"tagName\" in htmlElement && htmlElement.tagName === \"IMG\";\n}\n"],"names":[],"mappings":"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"}
|
package/model/createMapModel.js
CHANGED
|
@@ -13,6 +13,7 @@ import { INTERNAL_CONSTRUCTOR_TAG } from '../utils/InternalConstructorTag.js';
|
|
|
13
13
|
import { patchOpenLayersClassesForTesting } from '../utils/ol-test-support.js';
|
|
14
14
|
import { registerProjections } from '../utils/projections.js';
|
|
15
15
|
import { MapModel } from './MapModel.js';
|
|
16
|
+
import { sanitizeHtml } from '../utils/sanitize.js';
|
|
16
17
|
|
|
17
18
|
registerProjections({
|
|
18
19
|
"EPSG:25832": "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
|
|
@@ -169,8 +170,22 @@ function createDefaultAttribution(intl) {
|
|
|
169
170
|
element.role = "region";
|
|
170
171
|
element.ariaLabel = intl.formatMessage({ id: "attribution.label" });
|
|
171
172
|
}
|
|
173
|
+
sanitizeAttributionsHtml(attr);
|
|
172
174
|
return attr;
|
|
173
175
|
}
|
|
176
|
+
function sanitizeAttributionsHtml(attr) {
|
|
177
|
+
const originalCollectSourceAttributions = attr.collectSourceAttributions_;
|
|
178
|
+
if (!originalCollectSourceAttributions) {
|
|
179
|
+
throw new Error("Internal error: failed to override attributions widget");
|
|
180
|
+
}
|
|
181
|
+
attr.collectSourceAttributions_ = (frameState) => {
|
|
182
|
+
const attributions = originalCollectSourceAttributions.call(attr, frameState);
|
|
183
|
+
if (!Array.isArray(attributions)) {
|
|
184
|
+
throw new Error("Internal error: unexpected attributions result (should be an array)");
|
|
185
|
+
}
|
|
186
|
+
return attributions.map((a) => sanitizeHtml(a));
|
|
187
|
+
};
|
|
188
|
+
}
|
|
174
189
|
|
|
175
190
|
export { createMapModel };
|
|
176
191
|
//# sourceMappingURL=createMapModel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createMapModel.js","sources":["createMapModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch } from \"@conterra/reactivity-core\";\nimport { createLogger } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { MapBrowserEvent } from \"ol\";\nimport OlMap, { MapOptions } from \"ol/Map\";\nimport View, { ViewOptions } from \"ol/View\";\nimport Attribution from \"ol/control/Attribution\";\nimport { getCenter } from \"ol/extent\";\nimport { DragZoom, defaults as defaultInteractions } from \"ol/interaction\";\nimport TileLayer from \"ol/layer/Tile\";\nimport { Projection, get as getProjection } from \"ol/proj\";\nimport OSM from \"ol/source/OSM\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"../utils/InternalConstructorTag\";\nimport { patchOpenLayersClassesForTesting } from \"../utils/ol-test-support\";\nimport { registerProjections } from \"../utils/projections\";\nimport { MapConfig } from \"./MapConfig\";\nimport { MapModel } from \"./MapModel\";\n\n/**\n * Register custom projection to the global proj4js definitions. User can select `EPSG:25832`\n * and `EPSG:25833` from the predefined projections without calling `registerProjections`.\n */\nregisterProjections({\n \"EPSG:25832\":\n \"+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\",\n \"EPSG:25833\":\n \"+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\"\n});\nconst LOG = createLogger(sourceId);\n\nexport async function createMapModel(\n mapId: string,\n mapConfig: MapConfig,\n intl: PackageIntl,\n httpService: HttpService\n): Promise<MapModel> {\n return await new MapModelFactory(mapId, mapConfig, intl, httpService).createMapModel();\n}\n\nclass MapModelFactory {\n private mapId: string;\n private mapConfig: MapConfig;\n private intl: PackageIntl;\n private httpService: HttpService;\n\n constructor(mapId: string, mapConfig: MapConfig, intl: PackageIntl, httpService: HttpService) {\n this.mapId = mapId;\n this.mapConfig = mapConfig;\n this.intl = intl;\n this.httpService = httpService;\n }\n\n async createMapModel() {\n const mapId = this.mapId;\n const mapConfig = this.mapConfig;\n const { view: viewOption, ...rawOlOptions } = mapConfig.advanced ?? {};\n const mapOptions: MapOptions = {\n ...rawOlOptions\n };\n\n if (!mapOptions.controls) {\n mapOptions.controls = [createDefaultAttribution(this.intl)];\n }\n\n if (!mapOptions.interactions) {\n const shiftCtrlKeysOnly = (\n mapBrowserEvent: MapBrowserEvent<KeyboardEvent | WheelEvent | PointerEvent>\n ) => {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;\n };\n\n // setting altShiftDragRotate to false disables or excludes DragRotate interaction\n mapOptions.interactions = defaultInteractions({\n dragPan: true,\n altShiftDragRotate: false,\n pinchRotate: false,\n mouseWheelZoom: true\n }).extend([new DragZoom({ out: true, condition: shiftCtrlKeysOnly })]);\n }\n\n const view = (await viewOption) ?? {};\n this.initializeViewOptions(view);\n mapOptions.view = view instanceof View ? view : new View(view);\n\n if (!mapOptions.layers && !mapConfig.layers) {\n mapOptions.layers = [\n new TileLayer({\n source: new OSM()\n })\n ];\n }\n\n const initialView = mapConfig.initialView;\n const initialExtent = initialView?.kind === \"extent\" ? initialView.extent : undefined;\n\n LOG.debug(`Constructing OpenLayers map with options`, mapOptions);\n\n if (import.meta.env.VITEST) {\n patchOpenLayersClassesForTesting();\n }\n\n const olMap = new OlMap(mapOptions);\n const mapModel = new MapModel(\n {\n id: mapId,\n olMap,\n initialExtent,\n httpService: this.httpService\n },\n INTERNAL_CONSTRUCTOR_TAG\n );\n\n return batch(() => {\n try {\n if (mapConfig.layers) {\n for (const layerConfig of mapConfig.layers) {\n mapModel.layers.addLayer(layerConfig);\n }\n }\n return mapModel;\n } catch (e) {\n mapModel.destroy();\n throw e;\n }\n });\n }\n\n private initializeViewOptions(view: View | ViewOptions) {\n const mapId = this.mapId;\n const mapConfig = this.mapConfig;\n if (view instanceof View) {\n const warn = (prop: string) => {\n LOG.warn(\n `The advanced configuration for map id '${mapId}' has provided a fully constructed view instance: ${prop} cannot be applied.\\n` +\n `Use ViewOptions instead of a View instance.`\n );\n };\n\n if (mapConfig.projection != null) {\n warn(\"projection\");\n }\n if (mapConfig.initialView != null) {\n warn(\"initialView\");\n }\n return;\n }\n\n const projection = (view.projection = this.initializeProjection(mapConfig.projection));\n const initialView = mapConfig.initialView;\n if (initialView) {\n switch (initialView.kind) {\n case \"position\":\n view.zoom = initialView.zoom;\n view.center = [initialView.center.x, initialView.center.y];\n break;\n case \"extent\": {\n /*\n OpenLayers does not support configuration of the initial map extent.\n The only relevant options here are center, zoom (and resolution).\n We must set those values because otherwise OpenLayers will not initialize layer sources.\n\n The actual initial extent is applied once tha map has loaded and its size is known.\n */\n const extent = initialView.extent;\n view.zoom = 0;\n view.center = [\n extent.xMin + (extent.xMax - extent.xMin) / 2,\n extent.yMin + (extent.yMax - extent.yMin) / 2\n ];\n break;\n }\n }\n } else {\n this.setViewDefaults(view, projection);\n }\n }\n\n private setViewDefaults(view: ViewOptions, projection: Projection) {\n if (view.center == null) {\n const extent = projection.getExtent(); // can be null\n if (!extent) {\n LOG.warn(\n `Cannot set default center coordinate because the current projection has no associated extent.\\n` +\n `Try to configure 'initialView' explicity.`\n );\n } else {\n view.center = getCenter(extent);\n }\n }\n\n if (view.zoom == null || view.resolution == null) {\n view.zoom = 0;\n }\n }\n\n private initializeProjection(projectionOption: MapConfig[\"projection\"]) {\n if (projectionOption == null) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return getProjection(\"EPSG:3857\")!; // default OpenLayers projection\n }\n\n const projection = getProjection(projectionOption);\n if (!projection) {\n throw new Error(`Failed to retrieve projection for code '${projectionOption}'.`);\n }\n return projection;\n }\n}\n\nfunction createDefaultAttribution(intl: PackageIntl): Attribution {\n const attr = new Attribution({ collapsible: false });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const element = (attr as any).element as HTMLElement | undefined;\n if (element) {\n element.role = \"region\";\n element.ariaLabel = intl.formatMessage({ id: \"attribution.label\" });\n }\n return attr;\n}\n"],"names":["defaultInteractions","getProjection"],"mappings":";;;;;;;;;;;;;;;;AA0BA,mBAAA,CAAoB;AAAA,EAChB,YAAA,EACI,oFAAA;AAAA,EACJ,YAAA,EACI;AACR,CAAC,CAAA;AACD,MAAM,GAAA,GAAM,aAAa,QAAQ,CAAA;AAEjC,eAAsB,cAAA,CAClB,KAAA,EACA,SAAA,EACA,IAAA,EACA,WAAA,EACiB;AACjB,EAAA,OAAO,MAAM,IAAI,eAAA,CAAgB,KAAA,EAAO,WAAW,IAAA,EAAM,WAAW,EAAE,cAAA,EAAe;AACzF;AAEA,MAAM,eAAA,CAAgB;AAAA,EACV,KAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EAER,WAAA,CAAY,KAAA,EAAe,SAAA,EAAsB,IAAA,EAAmB,WAAA,EAA0B;AAC1F,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AAAA,EACvB;AAAA,EAEA,MAAM,cAAA,GAAiB;AACnB,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,MAAM,EAAE,MAAM,UAAA,EAAY,GAAG,cAAa,GAAI,SAAA,CAAU,YAAY,EAAC;AACrE,IAAA,MAAM,UAAA,GAAyB;AAAA,MAC3B,GAAG;AAAA,KACP;AAEA,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AACtB,MAAA,UAAA,CAAW,QAAA,GAAW,CAAC,wBAAA,CAAyB,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,IAC9D;AAEA,IAAA,IAAI,CAAC,WAAW,YAAA,EAAc;AAC1B,MAAA,MAAM,iBAAA,GAAoB,CACtB,eAAA,KACC;AACD,QAAA,MAAM,gBAAgB,eAAA,CAAgB,aAAA;AACtC,QAAA,OAAA,CAAQ,aAAA,CAAc,OAAA,IAAW,aAAA,CAAc,OAAA,KAAY,aAAA,CAAc,QAAA;AAAA,MAC7E,CAAA;AAGA,MAAA,UAAA,CAAW,eAAeA,QAAA,CAAoB;AAAA,QAC1C,OAAA,EAAS,IAAA;AAAA,QACT,kBAAA,EAAoB,KAAA;AAAA,QACpB,WAAA,EAAa,KAAA;AAAA,QACb,cAAA,EAAgB;AAAA,OACnB,CAAA,CAAE,MAAA,CAAO,CAAC,IAAI,QAAA,CAAS,EAAE,GAAA,EAAK,IAAA,EAAM,SAAA,EAAW,iBAAA,EAAmB,CAAC,CAAC,CAAA;AAAA,IACzE;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,UAAA,IAAe,EAAC;AACpC,IAAA,IAAA,CAAK,sBAAsB,IAAI,CAAA;AAC/B,IAAA,UAAA,CAAW,OAAO,IAAA,YAAgB,IAAA,GAAO,IAAA,GAAO,IAAI,KAAK,IAAI,CAAA;AAE7D,IAAA,IAAI,CAAC,UAAA,CAAW,MAAA,IAAU,CAAC,UAAU,MAAA,EAAQ;AACzC,MAAA,UAAA,CAAW,MAAA,GAAS;AAAA,QAChB,IAAI,SAAA,CAAU;AAAA,UACV,MAAA,EAAQ,IAAI,GAAA;AAAI,SACnB;AAAA,OACL;AAAA,IACJ;AAEA,IAAA,MAAM,cAAc,SAAA,CAAU,WAAA;AAC9B,IAAA,MAAM,aAAA,GAAgB,WAAA,EAAa,IAAA,KAAS,QAAA,GAAW,YAAY,MAAA,GAAS,MAAA;AAE5E,IAAA,GAAA,CAAI,KAAA,CAAM,4CAA4C,UAAU,CAAA;AAEhE,IAAA,IAAI,MAAA,CAAA,IAAA,CAAY,IAAI,MAAA,EAAQ;AACxB,MAAA,gCAAA,EAAiC;AAAA,IACrC;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,UAAU,CAAA;AAClC,IAAA,MAAM,WAAW,IAAI,QAAA;AAAA,MACjB;AAAA,QACI,EAAA,EAAI,KAAA;AAAA,QACJ,KAAA;AAAA,QACA,aAAA;AAAA,QACA,aAAa,IAAA,CAAK;AAAA,OACtB;AAAA,MACA;AAAA,KACJ;AAEA,IAAA,OAAO,MAAM,MAAM;AACf,MAAA,IAAI;AACA,QAAA,IAAI,UAAU,MAAA,EAAQ;AAClB,UAAA,KAAA,MAAW,WAAA,IAAe,UAAU,MAAA,EAAQ;AACxC,YAAA,QAAA,CAAS,MAAA,CAAO,SAAS,WAAW,CAAA;AAAA,UACxC;AAAA,QACJ;AACA,QAAA,OAAO,QAAA;AAAA,MACX,SAAS,CAAA,EAAG;AACR,QAAA,QAAA,CAAS,OAAA,EAAQ;AACjB,QAAA,MAAM,CAAA;AAAA,MACV;AAAA,IACJ,CAAC,CAAA;AAAA,EACL;AAAA,EAEQ,sBAAsB,IAAA,EAA0B;AACpD,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACtB,MAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAiB;AAC3B,QAAA,GAAA,CAAI,IAAA;AAAA,UACA,CAAA,uCAAA,EAA0C,KAAK,CAAA,kDAAA,EAAqD,IAAI,CAAA;AAAA,2CAAA;AAAA,SAE5G;AAAA,MACJ,CAAA;AAEA,MAAA,IAAI,SAAA,CAAU,cAAc,IAAA,EAAM;AAC9B,QAAA,IAAA,CAAK,YAAY,CAAA;AAAA,MACrB;AACA,MAAA,IAAI,SAAA,CAAU,eAAe,IAAA,EAAM;AAC/B,QAAA,IAAA,CAAK,aAAa,CAAA;AAAA,MACtB;AACA,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,aAAc,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,oBAAA,CAAqB,UAAU,UAAU,CAAA;AACpF,IAAA,MAAM,cAAc,SAAA,CAAU,WAAA;AAC9B,IAAA,IAAI,WAAA,EAAa;AACb,MAAA,QAAQ,YAAY,IAAA;AAAM,QACtB,KAAK,UAAA;AACD,UAAA,IAAA,CAAK,OAAO,WAAA,CAAY,IAAA;AACxB,UAAA,IAAA,CAAK,SAAS,CAAC,WAAA,CAAY,OAAO,CAAA,EAAG,WAAA,CAAY,OAAO,CAAC,CAAA;AACzD,UAAA;AAAA,QACJ,KAAK,QAAA,EAAU;AAQX,UAAA,MAAM,SAAS,WAAA,CAAY,MAAA;AAC3B,UAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AACZ,UAAA,IAAA,CAAK,MAAA,GAAS;AAAA,YACV,MAAA,CAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,IAAA,GAAO,OAAO,IAAA,IAAQ,CAAA;AAAA,YAC5C,MAAA,CAAO,IAAA,GAAA,CAAQ,MAAA,CAAO,IAAA,GAAO,OAAO,IAAA,IAAQ;AAAA,WAChD;AACA,UAAA;AAAA,QACJ;AAAA;AACJ,IACJ,CAAA,MAAO;AACH,MAAA,IAAA,CAAK,eAAA,CAAgB,MAAM,UAAU,CAAA;AAAA,IACzC;AAAA,EACJ;AAAA,EAEQ,eAAA,CAAgB,MAAmB,UAAA,EAAwB;AAC/D,IAAA,IAAI,IAAA,CAAK,UAAU,IAAA,EAAM;AACrB,MAAA,MAAM,MAAA,GAAS,WAAW,SAAA,EAAU;AACpC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACT,QAAA,GAAA,CAAI,IAAA;AAAA,UACA,CAAA;AAAA,yCAAA;AAAA,SAEJ;AAAA,MACJ,CAAA,MAAO;AACH,QAAA,IAAA,CAAK,MAAA,GAAS,UAAU,MAAM,CAAA;AAAA,MAClC;AAAA,IACJ;AAEA,IAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,IAAA,IAAQ,IAAA,CAAK,cAAc,IAAA,EAAM;AAC9C,MAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AAAA,IAChB;AAAA,EACJ;AAAA,EAEQ,qBAAqB,gBAAA,EAA2C;AACpE,IAAA,IAAI,oBAAoB,IAAA,EAAM;AAE1B,MAAA,OAAOC,IAAc,WAAW,CAAA;AAAA,IACpC;AAEA,IAAA,MAAM,UAAA,GAAaA,IAAc,gBAAgB,CAAA;AACjD,IAAA,IAAI,CAAC,UAAA,EAAY;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,gBAAgB,CAAA,EAAA,CAAI,CAAA;AAAA,IACnF;AACA,IAAA,OAAO,UAAA;AAAA,EACX;AACJ;AAEA,SAAS,yBAAyB,IAAA,EAAgC;AAC9D,EAAA,MAAM,OAAO,IAAI,WAAA,CAAY,EAAE,WAAA,EAAa,OAAO,CAAA;AAEnD,EAAA,MAAM,UAAW,IAAA,CAAa,OAAA;AAC9B,EAAA,IAAI,OAAA,EAAS;AACT,IAAA,OAAA,CAAQ,IAAA,GAAO,QAAA;AACf,IAAA,OAAA,CAAQ,YAAY,IAAA,CAAK,aAAA,CAAc,EAAE,EAAA,EAAI,qBAAqB,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,IAAA;AACX;;;;"}
|
|
1
|
+
{"version":3,"file":"createMapModel.js","sources":["createMapModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch } from \"@conterra/reactivity-core\";\nimport { createLogger } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport { PackageIntl } from \"@open-pioneer/runtime\";\nimport { MapBrowserEvent } from \"ol\";\nimport OlMap, { FrameState, MapOptions } from \"ol/Map\";\nimport View, { ViewOptions } from \"ol/View\";\nimport Attribution from \"ol/control/Attribution\";\nimport { getCenter } from \"ol/extent\";\nimport { DragZoom, defaults as defaultInteractions } from \"ol/interaction\";\nimport TileLayer from \"ol/layer/Tile\";\nimport { Projection, get as getProjection } from \"ol/proj\";\nimport OSM from \"ol/source/OSM\";\nimport { sourceId } from \"open-pioneer:source-info\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"../utils/InternalConstructorTag\";\nimport { patchOpenLayersClassesForTesting } from \"../utils/ol-test-support\";\nimport { registerProjections } from \"../utils/projections\";\nimport { MapConfig } from \"./MapConfig\";\nimport { MapModel } from \"./MapModel\";\nimport { sanitizeHtml } from \"../utils/sanitize\";\n\n/**\n * Register custom projection to the global proj4js definitions. User can select `EPSG:25832`\n * and `EPSG:25833` from the predefined projections without calling `registerProjections`.\n */\nregisterProjections({\n \"EPSG:25832\":\n \"+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\",\n \"EPSG:25833\":\n \"+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs\"\n});\nconst LOG = createLogger(sourceId);\n\nexport async function createMapModel(\n mapId: string,\n mapConfig: MapConfig,\n intl: PackageIntl,\n httpService: HttpService\n): Promise<MapModel> {\n return await new MapModelFactory(mapId, mapConfig, intl, httpService).createMapModel();\n}\n\nclass MapModelFactory {\n private mapId: string;\n private mapConfig: MapConfig;\n private intl: PackageIntl;\n private httpService: HttpService;\n\n constructor(mapId: string, mapConfig: MapConfig, intl: PackageIntl, httpService: HttpService) {\n this.mapId = mapId;\n this.mapConfig = mapConfig;\n this.intl = intl;\n this.httpService = httpService;\n }\n\n async createMapModel() {\n const mapId = this.mapId;\n const mapConfig = this.mapConfig;\n const { view: viewOption, ...rawOlOptions } = mapConfig.advanced ?? {};\n const mapOptions: MapOptions = {\n ...rawOlOptions\n };\n\n if (!mapOptions.controls) {\n mapOptions.controls = [createDefaultAttribution(this.intl)];\n }\n\n if (!mapOptions.interactions) {\n const shiftCtrlKeysOnly = (\n mapBrowserEvent: MapBrowserEvent<KeyboardEvent | WheelEvent | PointerEvent>\n ) => {\n const originalEvent = mapBrowserEvent.originalEvent;\n return (originalEvent.metaKey || originalEvent.ctrlKey) && originalEvent.shiftKey;\n };\n\n // setting altShiftDragRotate to false disables or excludes DragRotate interaction\n mapOptions.interactions = defaultInteractions({\n dragPan: true,\n altShiftDragRotate: false,\n pinchRotate: false,\n mouseWheelZoom: true\n }).extend([new DragZoom({ out: true, condition: shiftCtrlKeysOnly })]);\n }\n\n const view = (await viewOption) ?? {};\n this.initializeViewOptions(view);\n mapOptions.view = view instanceof View ? view : new View(view);\n\n if (!mapOptions.layers && !mapConfig.layers) {\n mapOptions.layers = [\n new TileLayer({\n source: new OSM()\n })\n ];\n }\n\n const initialView = mapConfig.initialView;\n const initialExtent = initialView?.kind === \"extent\" ? initialView.extent : undefined;\n\n LOG.debug(`Constructing OpenLayers map with options`, mapOptions);\n\n if (import.meta.env.VITEST) {\n patchOpenLayersClassesForTesting();\n }\n\n const olMap = new OlMap(mapOptions);\n const mapModel = new MapModel(\n {\n id: mapId,\n olMap,\n initialExtent,\n httpService: this.httpService\n },\n INTERNAL_CONSTRUCTOR_TAG\n );\n\n return batch(() => {\n try {\n if (mapConfig.layers) {\n for (const layerConfig of mapConfig.layers) {\n mapModel.layers.addLayer(layerConfig);\n }\n }\n return mapModel;\n } catch (e) {\n mapModel.destroy();\n throw e;\n }\n });\n }\n\n private initializeViewOptions(view: View | ViewOptions) {\n const mapId = this.mapId;\n const mapConfig = this.mapConfig;\n if (view instanceof View) {\n const warn = (prop: string) => {\n LOG.warn(\n `The advanced configuration for map id '${mapId}' has provided a fully constructed view instance: ${prop} cannot be applied.\\n` +\n `Use ViewOptions instead of a View instance.`\n );\n };\n\n if (mapConfig.projection != null) {\n warn(\"projection\");\n }\n if (mapConfig.initialView != null) {\n warn(\"initialView\");\n }\n return;\n }\n\n const projection = (view.projection = this.initializeProjection(mapConfig.projection));\n const initialView = mapConfig.initialView;\n if (initialView) {\n switch (initialView.kind) {\n case \"position\":\n view.zoom = initialView.zoom;\n view.center = [initialView.center.x, initialView.center.y];\n break;\n case \"extent\": {\n /*\n OpenLayers does not support configuration of the initial map extent.\n The only relevant options here are center, zoom (and resolution).\n We must set those values because otherwise OpenLayers will not initialize layer sources.\n\n The actual initial extent is applied once tha map has loaded and its size is known.\n */\n const extent = initialView.extent;\n view.zoom = 0;\n view.center = [\n extent.xMin + (extent.xMax - extent.xMin) / 2,\n extent.yMin + (extent.yMax - extent.yMin) / 2\n ];\n break;\n }\n }\n } else {\n this.setViewDefaults(view, projection);\n }\n }\n\n private setViewDefaults(view: ViewOptions, projection: Projection) {\n if (view.center == null) {\n const extent = projection.getExtent(); // can be null\n if (!extent) {\n LOG.warn(\n `Cannot set default center coordinate because the current projection has no associated extent.\\n` +\n `Try to configure 'initialView' explicity.`\n );\n } else {\n view.center = getCenter(extent);\n }\n }\n\n if (view.zoom == null || view.resolution == null) {\n view.zoom = 0;\n }\n }\n\n private initializeProjection(projectionOption: MapConfig[\"projection\"]) {\n if (projectionOption == null) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return getProjection(\"EPSG:3857\")!; // default OpenLayers projection\n }\n\n const projection = getProjection(projectionOption);\n if (!projection) {\n throw new Error(`Failed to retrieve projection for code '${projectionOption}'.`);\n }\n return projection;\n }\n}\n\nfunction createDefaultAttribution(intl: PackageIntl): Attribution {\n const attr = new Attribution({ collapsible: false });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const element = (attr as any).element as HTMLElement | undefined;\n if (element) {\n element.role = \"region\";\n element.ariaLabel = intl.formatMessage({ id: \"attribution.label\" });\n }\n sanitizeAttributionsHtml(attr);\n return attr;\n}\n\n// Overrides the OpenLayers widget to sanitize HTML attributions.\n// Note that this depends on OpenLayers internals that may change between versions.\nfunction sanitizeAttributionsHtml(attr: Attribution) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type\n const originalCollectSourceAttributions = (attr as any).collectSourceAttributions_ as Function;\n if (!originalCollectSourceAttributions) {\n throw new Error(\"Internal error: failed to override attributions widget\");\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (attr as any).collectSourceAttributions_ = (frameState: FrameState) => {\n const attributions = originalCollectSourceAttributions.call(attr, frameState) as string[];\n if (!Array.isArray(attributions)) {\n throw new Error(\"Internal error: unexpected attributions result (should be an array)\");\n }\n return attributions.map((a) => sanitizeHtml(a));\n };\n}\n"],"names":["defaultInteractions","getProjection"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@open-pioneer/map",
|
|
4
|
-
"version": "1.3.0-dev.
|
|
4
|
+
"version": "1.3.0-dev.20260225104836",
|
|
5
5
|
"description": "This package integrates OpenLayers maps into an open pioneer trails application.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"open-pioneer-trails"
|
package/utils/sanitize.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { AttributionLike } from "ol/source/Source";
|
|
2
1
|
/**
|
|
3
2
|
* Sanitizes the given raw html string.
|
|
4
3
|
*
|
|
5
4
|
* The result is safe to use as raw HTML in properties like `innerHTML`.
|
|
6
5
|
*/
|
|
7
6
|
export declare function sanitizeHtml(rawHtml: string): string;
|
|
8
|
-
/**
|
|
9
|
-
* Sanitizes an OpenLayers AttributionLike option.
|
|
10
|
-
*/
|
|
11
|
-
export declare function sanitizeAttributions(attributions: AttributionLike | undefined): AttributionLike | undefined;
|
package/utils/sanitize.js
CHANGED
|
@@ -4,31 +4,6 @@ const sanitizer = new Sanitizer();
|
|
|
4
4
|
function sanitizeHtml(rawHtml) {
|
|
5
5
|
return sanitizer.sanitize(rawHtml);
|
|
6
6
|
}
|
|
7
|
-
function sanitizeAttributions(attributions) {
|
|
8
|
-
if (!attributions) {
|
|
9
|
-
return attributions;
|
|
10
|
-
}
|
|
11
|
-
if (typeof attributions === "function") {
|
|
12
|
-
return function sanitizedAttributionFunction(...args) {
|
|
13
|
-
return sanitizeAttributionItems(attributions(...args));
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
return sanitizeAttributionItems(attributions);
|
|
17
|
-
}
|
|
18
|
-
function sanitizeAttributionItems(items) {
|
|
19
|
-
if (typeof items === "string") {
|
|
20
|
-
return sanitizeHtml(items);
|
|
21
|
-
}
|
|
22
|
-
if (Array.isArray(items)) {
|
|
23
|
-
return items.map((item) => {
|
|
24
|
-
if (typeof item === "string") {
|
|
25
|
-
return sanitizeHtml(item);
|
|
26
|
-
}
|
|
27
|
-
throw new Error("Expected a string");
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
throw new Error("Expected a string or an array of strings");
|
|
31
|
-
}
|
|
32
7
|
|
|
33
|
-
export {
|
|
8
|
+
export { sanitizeHtml };
|
|
34
9
|
//# sourceMappingURL=sanitize.js.map
|
package/utils/sanitize.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.js","sources":["sanitize.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Sanitizer } from \"@esri/arcgis-html-sanitizer\";\
|
|
1
|
+
{"version":3,"file":"sanitize.js","sources":["sanitize.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { Sanitizer } from \"@esri/arcgis-html-sanitizer\";\n\nconst sanitizer = new Sanitizer();\n\n/**\n * Sanitizes the given raw html string.\n *\n * The result is safe to use as raw HTML in properties like `innerHTML`.\n */\nexport function sanitizeHtml(rawHtml: string): string {\n return sanitizer.sanitize(rawHtml);\n}\n"],"names":[],"mappings":";;AAIA,MAAM,SAAA,GAAY,IAAI,SAAA,EAAU;AAOzB,SAAS,aAAa,OAAA,EAAyB;AAClD,EAAA,OAAO,SAAA,CAAU,SAAS,OAAO,CAAA;AACrC;;;;"}
|