diff --git a/app/helpers/gtt_map_helper.rb b/app/helpers/gtt_map_helper.rb
index caca1044..fb216248 100644
--- a/app/helpers/gtt_map_helper.rb
+++ b/app/helpers/gtt_map_helper.rb
@@ -32,7 +32,6 @@ def map_tag(map: nil, layers: map&.layers,
data[:popup] = popup if popup
data[:upload] = upload
data[:collapsed] = collapsed if collapsed
- data[:geocoding] = true if Setting.plugin_redmine_gtt['enable_geocoding_on_map'] == 'true'
uid = "ol-" + rand(36**8).to_s(36)
diff --git a/app/views/settings/gtt/_geocoder.html.erb b/app/views/settings/gtt/_geocoder.html.erb
index c0c6c6db..49e053d4 100644
--- a/app/views/settings/gtt/_geocoder.html.erb
+++ b/app/views/settings/gtt/_geocoder.html.erb
@@ -6,6 +6,19 @@
<%= check_box_tag 'settings[enable_geocoding_on_map]', true, @settings[:enable_geocoding_on_map] %>
+
+ <%= content_tag(:label, l(:geocoder_provider)) %>
+ <%= select_tag 'settings[default_geocoder_provider]',
+ options_for_select([
+ ['Google', 'google'],
+ ['Nominatim (OSM)', 'nominatim'],
+ ['Photon', 'photon'],
+ ['Custom', 'custom', {disabled: true}]
+ ], @settings['default_geocoder_provider']),
+ include_blank: true %>
+ <%= link_to t('geocoder_load_example'), '#', id: 'geocoder_load_example', class: 'info' %>
+
+
<%= content_tag(:label, l(:geocoder_options)) %>
<%= text_area_tag('settings[default_geocoder_options]',
@@ -15,3 +28,30 @@
:cols => 100) %>
+
+
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 9fbb5354..114876db 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -11,7 +11,9 @@ de:
label_gtt_select_icon: Icon auswählen
label_parameters: Parameter
label_tab_geocoder: Geocoder
- geocoder_options: Geocoder Optionen
+ geocoder_provider: "Anbieter"
+ geocoder_options: Optionen
+ geocoder_load_example: "Load example options"
gtt_settings_general_maxzoom_level: Standardwert für die maximale Zoomstufe der
Karte
label_default_collapsed_issues_page_map: Standardmäßig ausgeblendete Karte für Tickets
@@ -56,6 +58,9 @@ de:
control:
geocoding: Standort-Suche
geolocation: Mein Standort
+ search_location: "Search location"
+ reverse_location: "Click on the map to get location..."
+ search_placeholder: "Type a location..."
geolocation_notification_activated: "Geolocation activated"
geolocation_notification_deactivated: "Geolocation deactivated"
maximize: Zoom auf alle Objekte
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 5d1079fa..25e6e09e 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -28,7 +28,9 @@ en:
label_tab_general: "General"
label_tab_geocoder: "Geocoder"
- geocoder_options: "Geocoder Options"
+ geocoder_provider: "Provider"
+ geocoder_options: "Options"
+ geocoder_load_example: "Load example options"
gtt_map_rotate_label: "Map rotation"
gtt_map_rotate_info_html: "Hold down Shift+Alt
and drag the map to rotate."
@@ -100,6 +102,9 @@ en:
control:
geocoding: "Location search"
geolocation: "My location"
+ search_location: "Search location"
+ reverse_location: "Click on the map to get location..."
+ search_placeholder: "Type a location..."
geolocation_activated: "Geolocation activated"
geolocation_deactivated: "Geolocation deactivated"
maximize: "Zoom to all features"
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 8bc4aa82..8a828f13 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -28,7 +28,9 @@ ja:
label_tab_general: "一般"
label_tab_geocoder: "ジオコーダ"
- geocoder_options: "ジオコーダのオプション"
+ geocoder_provider: "Provider"
+ geocoder_options: "オプション"
+ geocoder_load_example: "Load example options"
gtt_map_rotate_label: "地図の回転"
gtt_map_rotate_info_html: "Shift+Alt
を押しながらドラッグして地図を回転します。"
@@ -100,6 +102,9 @@ ja:
control:
geocoding: 住所検索
geolocation: 現在地へ移動
+ search_location: "Search location"
+ reverse_location: "Click on the map to get location..."
+ search_placeholder: "Type a location..."
geolocation_notification_activated: "Geolocation activated"
geolocation_notification_deactivated: "Geolocation deactivated"
maximize: 地物にズーム
diff --git a/lib/redmine_gtt/hooks/view_layouts_base_html_head_hook.rb b/lib/redmine_gtt/hooks/view_layouts_base_html_head_hook.rb
index f06ac494..dd3eb130 100644
--- a/lib/redmine_gtt/hooks/view_layouts_base_html_head_hook.rb
+++ b/lib/redmine_gtt/hooks/view_layouts_base_html_head_hook.rb
@@ -13,15 +13,19 @@ def view_layouts_base_html_head(context={})
def view_layouts_base_body_bottom(context={})
tags = [];
- geocoder = {}
- geocoder_options = Setting.plugin_redmine_gtt['default_geocoder_options']
- if geocoder_options.present?
- begin
- geocoder = JSON.parse(geocoder_options)
- rescue JSON::ParserError => exception
- Rails.logger.warn "Failed to parse setting's 'geocoder_options' as JSON: #{exception}\nUse default '{}' instead."
- end
+
+ geocoder = {
+ enabled: false
+ }
+
+ if Setting.plugin_redmine_gtt['enable_geocoding_on_map'] == 'true'
+ geocoder = {
+ enabled: true,
+ provider: Setting.plugin_redmine_gtt['default_geocoder_provider'],
+ options: (JSON.parse(Setting.plugin_redmine_gtt['default_geocoder_options']) rescue {})
+ }
end
+
tags.push(tag.div :data => {
:lon => Setting.plugin_redmine_gtt['default_map_center_longitude'],
:lat => Setting.plugin_redmine_gtt['default_map_center_latitude'],
diff --git a/package.json b/package.json
index dcb51b27..084d4050 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"devDependencies": {
"@types/fontfaceobserver": "^2.1.3",
"@types/geojson": "^7946.0.14",
+ "@types/google.maps": "^3.55.9",
"@types/jquery": "^3.5.29",
"@types/jqueryui": "^1.12.21",
"@types/ol-ext": "npm:@siedlerchr/types-ol-ext",
diff --git a/src/components/gtt-client/geocoding/CustomButtonMixin.ts b/src/components/gtt-client/geocoding/CustomButtonMixin.ts
new file mode 100644
index 00000000..10575529
--- /dev/null
+++ b/src/components/gtt-client/geocoding/CustomButtonMixin.ts
@@ -0,0 +1,62 @@
+import ol_ext_element from 'ol-ext/util/element';
+
+export function applyCustomButton(searchControl: any, options: any) {
+ // Remove the default button if it exists
+ const defaultButton = searchControl.element.querySelector('button[type="button"]');
+ if (defaultButton) {
+ defaultButton.remove();
+ }
+
+ // Create a custom search button with a custom icon
+ searchControl.button = ol_ext_element.create('BUTTON', {
+ className: 'ol-search-gtt',
+ title: options.title || 'Search',
+ html: options.html || '',
+ parent: searchControl.element,
+ click: function () {
+ searchControl.element.classList.toggle('ol-collapsed');
+ if (!searchControl.element.classList.contains('ol-collapsed')) {
+ const input = searchControl.element.querySelector('input.search');
+ if (input) {
+ input.focus();
+ searchControl.drawList_();
+ }
+ }
+ }.bind(searchControl)
+ }) as HTMLButtonElement;
+
+ // Handle the reverse button if reverse geocoding is enabled
+ if (options.providerOptions.reverse) {
+ // Remove the default reverse button if it exists
+ const defaultReverseButton = searchControl.element.querySelector('button.ol-revers');
+ if (defaultReverseButton) {
+ defaultReverseButton.remove();
+ }
+
+ // Create a custom reverse button with a custom icon
+ searchControl.reverseButton = ol_ext_element.create('BUTTON', {
+ className: 'ol-search-gtt-reverse ol-revers',
+ title: options.providerOptions.reverseTitle || 'Click on the map',
+ html: options.html_reverse || 'X',
+ parent: searchControl.element,
+ click: function () {
+ if (!searchControl.get('reverse')) {
+ searchControl.set('reverse', !searchControl.get('reverse'));
+ const input = searchControl.element.querySelector('input.search');
+ if (input) {
+ input.focus();
+ searchControl.element.classList.add('ol-revers');
+ }
+ } else {
+ searchControl.set('reverse', false);
+ }
+ }.bind(searchControl)
+ }) as HTMLButtonElement;
+ }
+
+ // Move list to the end
+ const ul = searchControl.element.querySelector("ul.autocomplete");
+ if (ul) {
+ searchControl.element.appendChild(ul);
+ }
+}
diff --git a/src/components/gtt-client/geocoding/SearchFactory.ts b/src/components/gtt-client/geocoding/SearchFactory.ts
new file mode 100644
index 00000000..eecb6815
--- /dev/null
+++ b/src/components/gtt-client/geocoding/SearchFactory.ts
@@ -0,0 +1,58 @@
+// src/components/gtt-client/geocoding/SearchFactory.ts
+import { applyCustomButton } from './CustomButtonMixin';
+import SearchGTT from './SearchGTT';
+import SearchGoogle from './SearchGoogle';
+import SearchNominatim from 'ol-ext/control/SearchNominatim';
+import SearchPhoton from 'ol-ext/control/SearchPhoton';
+
+export function createSearchControl(options: any): any {
+ let searchControl: any;
+
+ // Create search control instance based on the provider
+ switch (options.provider) {
+ // Apply settings for Nomatim provider
+ case 'nominatim':
+ options.providerOptions = {
+ reverse: true, // Enable reverse geocoding
+ typing: -1, // Disable typing delay (see Nominatim policy!)
+ ...options.providerOptions,
+ };
+ searchControl = new SearchNominatim(options.providerOptions);
+ break;
+ // Apply settings for Photon provider
+ case 'photon':
+ options.providerOptions = {
+ // lang: 'en', // Force preferred language
+ reverse: true, // Enable reverse geocoding
+ position: true, // Priority to position
+ ...options.providerOptions,
+ };
+ searchControl = new SearchPhoton(options.providerOptions);
+ break;
+ // Apply settings for Google provider
+ case 'google':
+ options.providerOptions = {
+ reverse: true, // Enable reverse geocoding
+ ...options.providerOptions,
+ };
+ searchControl = new SearchGoogle(options.providerOptions);
+ break;
+
+ case 'custom':
+ options.providerOptions = {
+ ...options.providerOptions,
+ };
+ searchControl = new SearchGTT(options.providerOptions);
+ break;
+ // Add cases for new providers here
+ default:
+ // Throw an error if the provider is not supported
+ throw new Error(`Unsupported provider: ${options.provider}`);
+ break;
+ }
+
+ // Apply custom button implementation
+ applyCustomButton(searchControl, options);
+
+ return searchControl;
+}
diff --git a/src/components/gtt-client/geocoding/SearchGTT.ts b/src/components/gtt-client/geocoding/SearchGTT.ts
new file mode 100644
index 00000000..7c489345
--- /dev/null
+++ b/src/components/gtt-client/geocoding/SearchGTT.ts
@@ -0,0 +1,22 @@
+// src/components/gtt-client/geocoding/SearchGTT.ts
+import Search, { Options as SearchOptions } from 'ol-ext/control/Search';
+
+interface SearchGTTOptions extends SearchOptions {
+ // Add custom options here
+}
+
+/**
+ * Use this as a starting point for supporting a new geocoding service.
+ */
+class SearchGTT extends Search {
+ public button: HTMLButtonElement;
+
+ constructor(options: SearchGTTOptions = {}) {
+ options = options || {};
+ options.className = options.className || 'ol-search-gtt';
+
+ super(options);
+ }
+}
+
+export default SearchGTT;
diff --git a/src/components/gtt-client/geocoding/SearchGoogle.ts b/src/components/gtt-client/geocoding/SearchGoogle.ts
new file mode 100644
index 00000000..8966952f
--- /dev/null
+++ b/src/components/gtt-client/geocoding/SearchGoogle.ts
@@ -0,0 +1,198 @@
+import { transform as ol_proj_transform } from 'ol/proj.js';
+import SearchJSON, { Options as SearchOptions } from 'ol-ext/control/SearchJSON.js';
+import BaseEvent from 'ol/events/Event';
+
+/**
+ * @typedef {Object} SearchGoogleOptions
+ * @property {string} apiKey Google API key
+ * @property {string} [language] language code
+ * @property {string} [region] region code, specified as a ccTLD
+ * @property {string} [components] specifies the component restrictions (only Geocoding)
+ * @property {string} [result_type] filter the results to match a specific type (only Reverse Geocoding)
+ * @property {string} [location_type] filter the results to match a specific location type (only Reverse Geocoding)
+ */
+interface SearchGoogleOptions extends SearchOptions {
+ apiKey: string;
+ language?: string;
+ region?: string;
+ components?: string;
+ result_type?: string;
+ location_type?: string;
+}
+
+/**
+ * Search event
+ */
+export class SearchEvent extends BaseEvent {
+ public search: any;
+ public coordinate: any[];
+
+ constructor(type: string, search: any, coordinate: any[]) {
+ super(type);
+ this.search = search;
+ this.coordinate = coordinate;
+ }
+}
+
+/**
+ * Search places using the Google Geocoding API.
+ *
+ * @constructor
+ * @extends {SearchJSON}
+ * @fires select
+ * @param {Object=} options Control options.
+ * @param {string} options.className control class name
+ * @param {Element | string | undefined} options.target Specify a target if you want the control to be rendered outside of the map's viewport.
+ * @param {string | undefined} options.title Title to use for the search button tooltip, default "Search"
+ * @param {string | undefined} options.reverseTitle Title to use for the reverse geocoding button tooltip, default "Click on the map..."
+ * @param {string | undefined} options.placeholder placeholder, default "Search..."
+ * @param {number | undefined} options.typing a delay on each typing to start searching (ms), default 1000.
+ * @param {integer | undefined} options.minLength minimum length to start searching, default 3
+ * @param {integer | undefined} options.maxItems maximum number of items to display in the autocomplete list, default 10
+ * @param {function | undefined} options.handleResponse Handle server response to pass the features array to the list
+ * @param {string | undefined} options.apiKey Google API key (required)
+ * @param {string | undefined} options.language language code
+ * @param {string | undefined} options.region region code, specified as a ccTLD
+ * @param {string | undefined} options.components specifies the component restrictions (only Geocoding)
+ * @param {string | undefined} options.result_type filter the results to match a specific type (only Reverse Geocoding)
+ * @param {string | undefined} options.location_type filter the results to match a specific location type (only Reverse Geocoding)
+ */
+class SearchGoogle extends SearchJSON {
+ constructor(options: SearchGoogleOptions = { apiKey: null }) {
+ options.className = options.className || 'google';
+ options.url = options.url || 'https://maps.googleapis.com/maps/api/geocode/json';
+ super(options);
+
+ if (!options.apiKey) {
+ throw new Error('Google Geocoding API requires an API key');
+ }
+
+ this.set('apiKey', options.apiKey);
+
+ if (options.language) {
+ this.set('language', options.language);
+ }
+ if (options.region) {
+ this.set('region', options.region);
+ }
+ if (options.components) {
+ this.set('components', options.components);
+ }
+ if (options.result_type) {
+ this.set('result_type', options.result_type);
+ }
+ if (options.location_type) {
+ this.set('location_type', options.location_type);
+ }
+ }
+
+ /** Returns the text to be displayed in the menu
+ * @param {any} f the feature
+ * @return {string} the text to be displayed in the index
+ * @api
+ */
+ getTitle(f: any) {
+ return f.formatted_address;
+ }
+
+ /**
+ * @param {string} s the search string
+ * @return {Object} request data (as key:value)
+ * @api
+ */
+ requestData(s: string) {
+ const data: Record = {
+ address: s,
+ key: this.get('apiKey'),
+ };
+
+ const language = this.get('language');
+ if (language) {
+ data.language = language;
+ }
+
+ const region = this.get('region');
+ if (region) {
+ data.region = region;
+ }
+
+ const components = this.get('components');
+ if (components) {
+ data.components = components;
+ }
+
+ return data;
+ }
+
+ /**
+ * Handle server response to pass the features array to the list
+ * @param {any} response server response
+ * @return {Array} an array of feature
+ */
+ handleResponse(response: any): google.maps.GeocoderResult[] {
+ return response.results;
+ }
+
+ /** A line has been clicked in the menu > dispatch event
+ * @param {google.maps.GeocoderResult} f the feature, as passed in the autocomplete
+ * @api
+ */
+ select(f: any) {
+ var c = [f.geometry.location.lng, f.geometry.location.lat];
+ // Add coordinate to the event
+ try {
+ c = ol_proj_transform(c, 'EPSG:4326', this.getMap().getView().getProjection());
+ } catch (e) { /* ok */ }
+ this.dispatchEvent(new SearchEvent("select", f, c));
+ }
+
+ /** Reverse geocode
+ * @param {ol.coordinate} coord
+ * @api
+ */
+ reverseGeocode(coord: any, cback: (results: google.maps.GeocoderResult[]) => void) {
+ const lonlat = ol_proj_transform(coord, this.getMap().getView().getProjection(), 'EPSG:4326');
+ const baseUrl = this.get('url');
+
+ // Manually construct the query parameters to avoid double encoding the comma
+ let url = `${baseUrl}?latlng=${lonlat[1]},${lonlat[0]}&key=${this.get('apiKey')}`;
+
+ const language = this.get('language');
+ if (language) {
+ url += `&language=${encodeURIComponent(language)}`;
+ }
+
+ const region = this.get('region');
+ if (region) {
+ url += `®ion=${encodeURIComponent(region)}`;
+ }
+
+ const result_type = this.get('result_type');
+ if (result_type) {
+ url += `&result_type=${encodeURIComponent(result_type)}`;
+ }
+
+ const location_type = this.get('location_type');
+ if (location_type) {
+ url += `&location_type=${encodeURIComponent(location_type)}`;
+ }
+
+ this.ajax(
+ url,
+ {},
+ function (resp: any) {
+ if (cback) {
+ cback.call(this, resp.results);
+ } else {
+ if (resp && !resp.error) {
+ this._handleSelect(resp.results[0], true);
+ }
+ }
+ }.bind(this),
+ {}
+ );
+ }
+
+}
+
+export default SearchGoogle;
diff --git a/src/components/gtt-client/init/controls.ts b/src/components/gtt-client/init/controls.ts
index 455ba69e..fb2c9a42 100644
--- a/src/components/gtt-client/init/controls.ts
+++ b/src/components/gtt-client/init/controls.ts
@@ -6,9 +6,9 @@ import LayerSwitcher from 'ol-ext/control/LayerSwitcher';
import Notification from 'ol-ext/control/Notification';
import { position } from 'ol-ext/control/control';
-import { setGeocoding } from "../geocoding";
import { radiansToDegrees, degreesToRadians, parseHistory } from "../helpers";
import { zoomToExtent, setGeolocation, setView, setControls, setPopover } from "../openlayers";
+import { createSearchControl } from '../geocoding/SearchFactory';
/**
* Adds the toolbar and basic controls to the map instance.
@@ -20,11 +20,43 @@ function addToolbarAndControls(instance: any): void {
instance.map.addControl(instance.toolbar);
setView.call(instance);
- setGeocoding.call(instance, instance.map);
+ setSearchControl(instance);
setGeolocation.call(instance, instance.map);
parseHistory.call(instance);
}
+/**
+ * Adds the search control to the map instance.
+ * @param {any} map - The OpenLayers map instance.
+ */
+function setSearchControl(instance: any): void {
+ const geocoder = JSON.parse(instance.defaults.geocoder);
+
+ // Add the search control if enabled in plugin settings
+ if (JSON.parse(geocoder.enabled)) {
+ const searchControl = createSearchControl({
+ html: '',
+ html_reverse: '',
+ title: instance.i18n.control.search_location,
+ provider: geocoder.provider,
+ providerOptions: {
+ reverseTitle: instance.i18n.control.reverse_location,
+ placeholder: instance.i18n.control.search_placeholder,
+ ...geocoder.options
+ },
+ });
+ instance.map.addControl(searchControl);
+
+ // Add a listener for the select event
+ searchControl.on('select', function(evt: any) {
+ instance.map.getView().animate({
+ center: evt.coordinate,
+ zoom: Math.max(instance.map.getView().getZoom(), 18)
+ });
+ });
+ }
+}
+
/**
* Adds the FullScreen and Rotate controls to the map instance.
* @param {any} instance - The GttClient instance.
diff --git a/src/styles/scss/app.scss b/src/styles/scss/app.scss
index f34c60fe..393b9fb4 100644
--- a/src/styles/scss/app.scss
+++ b/src/styles/scss/app.scss
@@ -61,8 +61,17 @@ $breakpoint-tablet: 899px;
background-color: rgba(52, 73, 94, 1);
}
+// Unset default search icon
+.ol-control.ol-search > button::before,
+.ol-control.ol-search > button::after {
+ content: none;
+}
+
+// Increase button icon size
.ol-zoom button.ol-zoom-in,
.ol-zoom button.ol-zoom-out,
+.ol-search button.ol-search-gtt,
+.ol-search button.ol-search-gtt-reverse,
.ol-full-screen button.ol-full-screen-true,
.ol-full-screen button.ol-full-screen-false,
.ol-rotate button.ol-rotate-reset,
@@ -70,6 +79,23 @@ $breakpoint-tablet: 899px;
font-size: 1.5rem;
}
+.ol-search input.search {
+ padding: 1.0em;
+ font-size: 1.0rem;
+}
+
+.ol-search ul.autocomplete li.copy {
+ font-size: 0.7rem;
+ background-color: rgba(52, 73, 94, 0.8);
+}
+
+// Adjust search indicator animation
+.ol-search.searching:before {
+ height: 3px;
+ top: 2.0em;
+ background: red;
+}
+
div.ol-full-screen {
right: 2.55rem;
}
diff --git a/tsconfig.json b/tsconfig.json
index c78fe4fe..0c7237a8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "target": "es5",
+ "target": "es6",
"module": "es6",
"moduleResolution": "node",
"jsx": "react",
@@ -8,6 +8,10 @@
"outDir": "./dist",
"allowJs": true,
"noImplicitAny": true,
+ // "strict": true,
+ // "esModuleInterop": true,
+ // "skipLibCheck": true,
+ // "sourceMap": true,
"paths": {
"*": ["@types/*"]
}
diff --git a/yarn.lock b/yarn.lock
index 4d744a81..fce02836 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,13 +2,6 @@
# yarn lockfile v1
-"@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0":
- version "7.21.5"
- resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz"
- integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
- dependencies:
- regenerator-runtime "^0.13.11"
-
"@discoveryjs/json-ext@^0.5.0":
version "0.5.7"
resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz"
@@ -152,6 +145,11 @@
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613"
integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==
+"@types/google.maps@^3.55.9":
+ version "3.55.9"
+ resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.55.9.tgz#3bbe1d044d9b999392a359fb37b0de2545ac53c4"
+ integrity sha512-phaOMtezbT3NaXPKiI3m0OosUS7Nly0auw3Be5s/CgMWLVoDAUP1Yb/Ld0TRoRp8ibrlT4VqM5kmzfvUA0UNLQ==
+
"@types/jquery@*":
version "3.5.16"
resolved "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz"
@@ -184,16 +182,9 @@
integrity sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q==
"@types/ol-ext@npm:@siedlerchr/types-ol-ext":
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/@siedlerchr/types-ol-ext/-/types-ol-ext-3.2.4.tgz#5411370c5cc62db6f5fddbe6c5dba203c19aeba3"
- integrity sha512-d6auH1slNSyR6v2gP0J2fFPdgvRetAcThASZrcA65lciZmewRgDJaryaCj6/hjvEopokaE4KaMc1OkO8LdRNOw==
- dependencies:
- jspdf "^2.5.1"
-
-"@types/raf@^3.4.0":
version "3.4.0"
- resolved "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz"
- integrity sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==
+ resolved "https://registry.yarnpkg.com/@siedlerchr/types-ol-ext/-/types-ol-ext-3.4.0.tgz#e57292b89fc6b00226a751479c41e78d266c283a"
+ integrity sha512-LtS9YNitiQ2UZV+RHVOS0Pehlkpcsp6qX9Sa2I33l4ZNqFCRB0T8YefGj0Se4SP8cPr1jc9+q1UU86BjFpg8ww==
"@types/sizzle@*":
version "2.3.3"
@@ -391,16 +382,6 @@ anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"
-atob@^2.1.2:
- version "2.1.2"
- resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz"
- integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
-
-base64-arraybuffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz"
- integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
-
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
@@ -423,11 +404,6 @@ browserslist@^4.21.10:
node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
-btoa@^1.2.1:
- version "1.2.1"
- resolved "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz"
- integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
-
buffer-from@^1.0.0:
version "1.1.2"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
@@ -438,20 +414,6 @@ caniuse-lite@^1.0.30001580:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001584.tgz#5e3ea0625d048d5467670051687655b1f7bf7dfd"
integrity sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ==
-canvg@^3.0.6:
- version "3.0.10"
- resolved "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz"
- integrity sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==
- dependencies:
- "@babel/runtime" "^7.12.5"
- "@types/raf" "^3.4.0"
- core-js "^3.8.3"
- raf "^3.4.1"
- regenerator-runtime "^0.13.7"
- rgbcolor "^1.0.1"
- stackblur-canvas "^2.0.0"
- svg-pathdata "^6.0.3"
-
chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
@@ -536,11 +498,6 @@ commander@^2.20.0:
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-core-js@^3.6.0, core-js@^3.8.3:
- version "3.30.2"
- resolved "https://registry.npmjs.org/core-js/-/core-js-3.30.2.tgz"
- integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==
-
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
@@ -550,13 +507,6 @@ cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
-css-line-break@^2.1.0:
- version "2.1.0"
- resolved "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz"
- integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
- dependencies:
- utrie "^1.0.2"
-
css-loader@^6.10.0:
version "6.10.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.10.0.tgz#7c172b270ec7b833951b52c348861206b184a4b7"
@@ -581,11 +531,6 @@ cssesc@^3.0.0:
resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
-dompurify@^2.2.0:
- version "2.4.5"
- resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.4.5.tgz"
- integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==
-
earcut@^2.2.3:
version "2.2.4"
resolved "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz"
@@ -672,11 +617,6 @@ fastest-levenshtein@^1.0.12:
resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz"
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
-fflate@^0.4.8:
- version "0.4.8"
- resolved "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz"
- integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
-
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
@@ -754,14 +694,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
-html2canvas@^1.0.0-rc.5:
- version "1.4.1"
- resolved "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz"
- integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
- dependencies:
- css-line-break "^2.1.0"
- text-segmentation "^1.0.3"
-
icss-utils@^5.0.0, icss-utils@^5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz"
@@ -862,21 +794,6 @@ json-stringify-pretty-compact@^2.0.0:
resolved "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz"
integrity sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==
-jspdf@^2.5.1:
- version "2.5.1"
- resolved "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz"
- integrity sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==
- dependencies:
- "@babel/runtime" "^7.14.0"
- atob "^2.1.2"
- btoa "^1.2.1"
- fflate "^0.4.8"
- optionalDependencies:
- canvg "^3.0.6"
- core-js "^3.6.0"
- dompurify "^2.2.0"
- html2canvas "^1.0.0-rc.5"
-
kind-of@^6.0.2:
version "6.0.3"
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
@@ -1038,11 +955,6 @@ pbf@3.2.1:
ieee754 "^1.1.12"
resolve-protobuf-schema "^2.1.0"
-performance-now@^2.1.0:
- version "2.1.0"
- resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz"
- integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
-
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
@@ -1130,13 +1042,6 @@ quickselect@^2.0.0:
resolved "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz"
integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
-raf@^3.4.1:
- version "3.4.1"
- resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"
- integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
- dependencies:
- performance-now "^2.1.0"
-
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
@@ -1165,11 +1070,6 @@ rechoir@^0.8.0:
dependencies:
resolve "^1.20.0"
-regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.7:
- version "0.13.11"
- resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
- integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
-
resolve-cwd@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz"
@@ -1198,11 +1098,6 @@ resolve@^1.20.0:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-rgbcolor@^1.0.1:
- version "1.0.1"
- resolved "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz"
- integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==
-
rw@^1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz"
@@ -1328,11 +1223,6 @@ source-map@^0.7.4:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
-stackblur-canvas@^2.0.0:
- version "2.5.0"
- resolved "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz"
- integrity sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==
-
style-loader@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7"
@@ -1357,11 +1247,6 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-svg-pathdata@^6.0.3:
- version "6.0.3"
- resolved "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz"
- integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==
-
tapable@^2.1.1, tapable@^2.2.0:
version "2.2.1"
resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"
@@ -1388,13 +1273,6 @@ terser@^5.26.0:
commander "^2.20.0"
source-map-support "~0.5.20"
-text-segmentation@^1.0.3:
- version "1.0.3"
- resolved "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz"
- integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
- dependencies:
- utrie "^1.0.2"
-
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
@@ -1438,13 +1316,6 @@ util-deprecate@^1.0.2:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-utrie@^1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz"
- integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
- dependencies:
- base64-arraybuffer "^1.0.2"
-
watchpack@^2.4.0:
version "2.4.0"
resolved "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz"