diff --git a/examples/snowbox/index.js b/examples/snowbox/index.js index 8134d89c56..2fc418252b 100644 --- a/examples/snowbox/index.js +++ b/examples/snowbox/index.js @@ -19,6 +19,7 @@ import pluginLoadingIndicator from '@polar/polar/plugins/loadingIndicator' import pluginPins from '@polar/polar/plugins/pins' import pluginPointerPosition from '@polar/polar/plugins/pointerPosition' import pluginReverseGeocoder from '@polar/polar/plugins/reverseGeocoder' +import pluginRouting from '@polar/polar/plugins/routing' import pluginScale from '@polar/polar/plugins/scale' import pluginToast from '@polar/polar/plugins/toast' import pluginZoom from '@polar/polar/plugins/zoom' @@ -488,6 +489,16 @@ addPlugin( }, */ }), }, + { + plugin: pluginRouting({ + type: 'ors', + url: 'https://api.openrouteservice.org/v2/directions/', + apiKey: '', + displayPreferences: true, + displayRouteTypesToAvoid: true, + }), + icon: 'kern-icon-fill--assistant-direction', + }, ], [ { diff --git a/src/architecture.spec.ts b/src/architecture.spec.ts index 4f524b9f54..a35db3ba20 100644 --- a/src/architecture.spec.ts +++ b/src/architecture.spec.ts @@ -35,7 +35,7 @@ describe('Architectural checks', () => { .matchingPattern('^plugins/.*$') .should() .matchPattern( - '^plugins/[^/]+/((index|locales|store|types)\\.ts|utils/.*\\.ts|components/.*\\.spec\\.ts|stores/.*\\.ts)$' + '^plugins/[^/]+/((index|locales|store|types)\\.ts|utils/.*\\.ts|components/.*\\.spec\\.ts|stores/.*\\.ts|composables/.*\\.ts)$' ) .check() expect(violations).toEqual([]) diff --git a/src/client.ts b/src/client.ts index 0595ad1159..6fc6cd943b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -20,6 +20,7 @@ import LoadingIndicator from '@/plugins/loadingIndicator' import Pins from '@/plugins/pins' import PointerPosition from '@/plugins/pointerPosition' import ReverseGeocoder from '@/plugins/reverseGeocoder' +import Routing from '@/plugins/routing' import Scale from '@/plugins/scale' import Toast from '@/plugins/toast' @@ -39,6 +40,9 @@ function addPlugins(map: typeof PolarContainer, enabledPlugins: string[]) { enabledPlugins.includes('geoLocation') && { plugin: GeoLocation({ renderType: 'iconMenu' }), }, + enabledPlugins.includes('routing') && { + plugin: Routing({ type: 'ors', url: '' }), + }, ].filter((x) => x) as Menu[], ], }) @@ -85,10 +89,10 @@ function addPlugins(map: typeof PolarContainer, enabledPlugins: string[]) { * * @param containerId - ID of the container the map will render itself in. * @param serviceRegister - Service register given as an array, or a URL to fetch this from. - * @param mapConfiguration - Configuration options. Only plugins that have a configuration will be created. To - * enable a plugin with default configuration, add its key with an empty object. The - * plugins with the ids 'fullscreen', 'geoLocation' and 'layerChooser' are added to the iconMenu. - * IconMenu. The IconMenu, Toast, LayerChooser and LoadingIndicator are enabled by default. + * @param mapConfiguration - Configuration options. Only plugins that have a configuration will be created. + * To enable a plugin with default configuration, add its key with an empty object. + * The plugins with the ids 'fullscreen', 'geoLocation', 'routing' and 'layerChooser' are added + * to the IconMenu. The IconMenu, Toast, LayerChooser and LoadingIndicator are enabled by default. * @param modifyServiceRegister - Optionally modify the serviceRegister. This may be useful if a pre-existing register is used. * * @example diff --git a/src/components/PolarSelect.ce.vue b/src/components/PolarSelect.ce.vue index bec61559ff..b9689665e0 100644 --- a/src/components/PolarSelect.ce.vue +++ b/src/components/PolarSelect.ce.vue @@ -30,12 +30,14 @@ + + diff --git a/src/plugins/routing/components/RoutingInput.ce.vue b/src/plugins/routing/components/RoutingInput.ce.vue new file mode 100644 index 0000000000..72743b834e --- /dev/null +++ b/src/plugins/routing/components/RoutingInput.ce.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/plugins/routing/components/RoutingOptions.ce.vue b/src/plugins/routing/components/RoutingOptions.ce.vue new file mode 100644 index 0000000000..ff2620fadf --- /dev/null +++ b/src/plugins/routing/components/RoutingOptions.ce.vue @@ -0,0 +1,54 @@ + + + diff --git a/src/plugins/routing/components/RoutingWrapper.ce.vue b/src/plugins/routing/components/RoutingWrapper.ce.vue new file mode 100644 index 0000000000..b258c19e84 --- /dev/null +++ b/src/plugins/routing/components/RoutingWrapper.ce.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/plugins/routing/composables/useLayer.ts b/src/plugins/routing/composables/useLayer.ts new file mode 100644 index 0000000000..3d24b8e9c2 --- /dev/null +++ b/src/plugins/routing/composables/useLayer.ts @@ -0,0 +1,20 @@ +import type { Map } from 'ol' +import type VectorSource from 'ol/source/Vector' + +import VectorLayer from 'ol/layer/Vector' +import { Stroke, Style } from 'ol/style' +import { onScopeDispose } from 'vue' + +export function useLayer(map: Map, routeSource: VectorSource) { + const layer = new VectorLayer({ + source: routeSource, + style: new Style({ + stroke: new Stroke({ color: 'blue', width: 6 }), + }), + }) + + map.addLayer(layer) + onScopeDispose(() => { + map.removeLayer(layer) + }) +} diff --git a/src/plugins/routing/index.ts b/src/plugins/routing/index.ts new file mode 100644 index 0000000000..03eef06327 --- /dev/null +++ b/src/plugins/routing/index.ts @@ -0,0 +1,41 @@ +/* eslint-disable tsdoc/syntax */ +/** + * @module \@polar/polar/plugins/routing + */ +/* eslint-enable tsdoc/syntax */ + +import type { PluginContainer, PolarPluginStore } from '@/core' +import type { RoutingPluginOptions } from './types' + +import component from './components/RoutingWrapper.ce.vue' +import locales from './locales' +import { useRoutingStore } from './store' +import { PluginId } from './types' + +/** + * Creates a plugin which offers routing functionality to the user. + * + * A user can select multiple waypoints by clicking on the map. + * If at least two waypoints have been added, the route is automatically calculated and displayed on the map. + * + * The travel mode can be adjusted as well as the types of routes to avoid. + * Similarly, the route preference is set to `'recommended'` by default, but can be changed to `'fastest'` or `'shortest'`. + * + * Once a route is available, a detailed listing of every route segment is available including instructions, distance and duration. + * + * @returns Plugin for use with {@link addPlugin}. + */ +export default function pluginRouting( + options: RoutingPluginOptions +): PluginContainer { + return { + id: PluginId, + component, + locales, + icon: 'kern-icon-fill--assistant-direction', + storeModule: useRoutingStore as PolarPluginStore, + options, + } +} + +export * from './types' diff --git a/src/plugins/routing/locales.ts b/src/plugins/routing/locales.ts new file mode 100644 index 0000000000..1d9c425b5c --- /dev/null +++ b/src/plugins/routing/locales.ts @@ -0,0 +1,103 @@ +/* eslint-disable tsdoc/syntax */ +/** + * This is the documentation for the locales keys in the routing plugin. + * These locales are *NOT* exported, but documented only. + * + * @module locales/plugins/routing + */ +/* eslint-enable tsdoc/syntax */ + +import type { Locale } from '@/core' + +export const resourcesDe = { + title: 'Routenplaner', + label: { + aria: 'Durch Klicken in die Karte eine Koordinate als {{position}} auswählen.', + start: 'Start', + middle: 'Wegpunkt', + end: 'Ziel', + add: 'Wegpunkt hinzufügen', + remove: 'Wegpunkt entfernen', + travelMode: 'Fortbewegungsart', + preference: 'Bevorzugte Route', + avoid: 'Verkehrswege meiden', + reset: 'Zurücksetzen', + details: 'Details zur Route', + steps: 'Routenanweisungen', + }, + travelMode: { + car: 'Auto', + hgv: 'LKW', + bike: 'Fahrrad', + walking: 'Zu Fuß', + wheelchair: 'Rollstuhl', + }, + preference: { + recommended: 'Empfohlen', + fastest: 'Schnellste', + shortest: 'Kürzeste', + }, + avoid: { + highways: 'Autobahnen', + tollways: 'Mautstraßen', + ferries: 'Fähren', + }, + ariaLive: `Route berechnet: {{steps}} Schritte, {{duration}}, {{distance}}.`, + distance: 'Entfernung: {{distance}}', + duration: 'Dauer: {{duration}}', + noFeature: + 'Die Route konnte nicht ermittelt werden. Versuchen Sie es mit anderen Koordinaten.', +} as const + +export const resourcesEn = { + title: 'Route Planner', + label: { + aria: 'Add a coordinate as {{position}} by clicking in the map.', + start: 'Start', + middle: 'Waypoint', + end: 'Destination', + add: 'Add waypoint', + remove: 'Remove waypoint', + travelMode: 'Travel Mode', + preference: 'Preferred Route', + avoid: 'Types of routes to avoid', + reset: 'Reset', + details: 'Route Details', + steps: 'Route instructions', + }, + travelMode: { + car: 'Car', + hgv: 'Heavy Goods Vehicle', + bike: 'Bike', + walking: 'Walking', + wheelchair: 'Wheelchair', + }, + preference: { + recommended: 'Recommended', + fastest: 'Fastest', + shortest: 'Shortest', + }, + avoid: { + highways: 'Highways', + tollways: 'Tollways', + ferries: 'Ferries', + }, + ariaLive: `Route calculated: {{steps}} steps, {{duration}}, {{distance}}.`, + distance: 'Distance: {{distance}}', + duration: 'Duration: {{duration}}', + noFeature: 'Route could not be determined. Try different coordinates.', +} as const + +// first type will be used as fallback language +const locales: Locale[] = [ + { + type: 'de', + resources: resourcesDe, + }, + { + type: 'en', + resources: resourcesEn, + }, +] + +export default locales diff --git a/src/plugins/routing/store.ts b/src/plugins/routing/store.ts new file mode 100644 index 0000000000..e2fcd9fbc5 --- /dev/null +++ b/src/plugins/routing/store.ts @@ -0,0 +1,441 @@ +/* eslint-disable tsdoc/syntax */ +/** + * @module \@polar/polar/plugins/routing/store + */ +/* eslint-enable tsdoc/syntax */ + +import type { Coordinate } from 'ol/coordinate' +import type { Point } from 'ol/geom' +import type { + RoutingPluginOptions, + RoutingResponseData, + SelectableTravelMode, + TravelMode, +} from './types' + +import { t } from 'i18next' +import { Feature } from 'ol' +import { LineString } from 'ol/geom' +import Draw from 'ol/interaction/Draw' +import { transform } from 'ol/proj' +import VectorSource from 'ol/source/Vector' +import { acceptHMRUpdate, defineStore } from 'pinia' +import { computed, ref, watch } from 'vue' + +import { useCoreStore } from '@/core/stores' +import { computedT } from '@/lib/computedT' + +import { useLayer } from './composables/useLayer' +import { PluginId } from './types' +import { handleErrors } from './utils/handleErrors' + +/* eslint-disable tsdoc/syntax */ +/** + * @function + * + * Plugin store for routing. + */ +/* eslint-enable tsdoc/syntax */ +export const useRoutingStore = defineStore('plugins/routing', () => { + const coreStore = useCoreStore() + + const routeSource = new VectorSource() + let abortController: AbortController | null = null + let draw: Draw | undefined + + const _currentlyFocusedInput = ref(-1) + const route = ref([[], []]) + const routingResponseData = ref(null) + const selectedPreference = ref('recommended') + const selectedRouteTypesToAvoid = ref([]) + const selectedTravelMode = ref('driving-car') + + const configuration = computed( + () => (coreStore.configuration.routing || {}) as RoutingPluginOptions + ) + const currentlyFocusedInput = computed({ + get: () => _currentlyFocusedInput.value, + set: (index) => { + _currentlyFocusedInput.value = index + + if (index !== -1) { + coreStore.map.addInteraction(draw as Draw) + } else { + coreStore.map.removeInteraction(draw as Draw) + } + }, + }) + const routeIncomplete = computed(() => + route.value.some((part) => part.length === 0) + ) + const routeAsWGS84 = computed(() => + route.value.map((coordinate) => + transform( + coordinate, + coreStore.map.getView().getProjection().getCode(), + 'EPSG:4326' + ) + ) + ) + const routeFeature = computed( + () => routingResponseData.value?.features[0] ?? null + ) + const showDetails = computed(() => routingResponseData.value !== null) + const url = computed( + () => configuration.value.url + selectedTravelMode.value + '/geojson' + ) + const displayPreferences = computed( + () => coreStore.configuration.routing?.displayPreferences || false + ) + const selectablePreferences = computed(() => + ['recommended', 'fastest', 'shortest'].map((value) => ({ + value, + label: computedT(() => t(($) => $.preference[value], { ns: PluginId })), + })) + ) + const displayRouteTypesToAvoid = computed( + () => coreStore.configuration.routing?.displayRouteTypesToAvoid || false + ) + const selectableRouteTypesToAvoid = computed(() => + selectedTravelMode.value === 'driving-car' || + selectedTravelMode.value === 'driving-hgv' + ? ['highways', 'tollways', 'ferries'] + : ['ferries'] + ) + const selectableTravelModes = computed( + () => + coreStore.configuration.routing?.selectableTravelModes || [ + 'driving-car', + 'cycling-regular', + 'foot-walking', + ] + ) + const travelModes = computed(() => + ( + [ + { + value: 'driving-car', + label: computedT(() => t(($) => $.travelMode.car, { ns: PluginId })), + icon: 'kern-icon--directions-car', + }, + { + value: 'driving-hgv', + label: computedT(() => t(($) => $.travelMode.hgv, { ns: PluginId })), + icon: 'kern-icon--local-shipping', + }, + { + value: 'cycling-regular', + label: computedT(() => t(($) => $.travelMode.bike, { ns: PluginId })), + icon: 'kern-icon--directions-bike', + }, + { + value: 'foot-walking', + label: computedT(() => + t(($) => $.travelMode.walking, { ns: PluginId }) + ), + icon: 'kern-icon--directions-walk', + }, + { + value: 'wheelchair', + label: computedT(() => + t(($) => $.travelMode.wheelchair, { ns: PluginId }) + ), + icon: 'kern-icon--accessible', + }, + ] as TravelMode[] + ).filter(({ value }) => selectableTravelModes.value.includes(value)) + ) + + function addCoordinateToRoute(coordinate: Coordinate) { + route.value = route.value.toSpliced( + currentlyFocusedInput.value, + 1, + coordinate + ) + } + + async function fetchRoute(signal: AbortSignal): Promise { + const response = await fetch(url.value, { + method: 'POST', + headers: { + /* eslint-disable @typescript-eslint/naming-convention */ + 'Content-Type': 'application/json', + ...(configuration.value.apiKey && { + Authorization: configuration.value.apiKey, + }), + /* eslint-enable @typescript-eslint/naming-convention */ + }, + body: JSON.stringify({ + coordinates: routeAsWGS84.value, + geometry: true, + instructions: true, + language: coreStore.language, + options: { + avoid_features: selectedRouteTypesToAvoid.value, + }, + preference: selectedPreference.value, + units: 'm', + }), + signal, + }) + if (!response.ok) { + throw new Error( + 'Route could not be determined. Try different coordinates.' + ) + } + return response.json() + } + + async function getRoute() { + routeSource.clear() + if (abortController) { + abortController.abort() + } + abortController = new AbortController() + const { signal } = abortController + try { + routingResponseData.value = await fetchRoute(signal) + + if (!routeFeature.value) { + throw new Error(t(($) => $.noFeature, { ns: PluginId })) + } + routeSource.addFeature( + new Feature({ + geometry: new LineString( + routeFeature.value.geometry.coordinates.map((coordinate) => + transform( + coordinate, + 'EPSG:4326', + coreStore.map.getView().getProjection().getCode() + ) + ) + ), + }) + ) + } catch (error) { + if (!signal.aborted) { + handleErrors(error) + } + } + } + + function initializeDraw() { + draw = new Draw({ stopClick: true, type: 'Point' }) + // @ts-expect-error | internal hack to detect it in @polar/plugin-pins and @polar/plugin-gfi + draw._isRoutingDraw = true + draw.on('drawend', (e) => { + addCoordinateToRoute((e.feature.getGeometry() as Point).getCoordinates()) + // @ts-expect-error | internal hack to detect it in @polar/plugin-pins and @polar/plugin-gfi + draw._isRoutingDraw = false + currentlyFocusedInput.value = -1 + }) + } + + function updateFocus(event: Event) { + if (currentlyFocusedInput.value === -1) { + return + } + const path = event.composedPath() + const isRoutingInput = path.some( + (el) => + el instanceof HTMLElement && + el.id.startsWith('polar-plugin-routing-input-') + ) + if (!isRoutingInput && !path.includes(coreStore.map.getTargetElement())) { + currentlyFocusedInput.value = -1 + } + } + + watch( + [ + route, + selectedPreference, + selectedRouteTypesToAvoid, + selectedTravelMode, + () => coreStore.language, + ], + () => { + if (!routeIncomplete.value) { + void getRoute() + } + } + ) + watch(selectedTravelMode, () => { + selectedRouteTypesToAvoid.value = [] + }) + + useLayer(coreStore.map, routeSource) + + function setupPlugin() { + initializeDraw() + // `pointerdown` handles mouse interaction while `focusin` handles keyboard + // navigation (e.g. tabbing) away from the routing inputs. + ;(coreStore.shadowRoot as ShadowRoot).addEventListener( + 'pointerdown', + updateFocus + ) + ;(coreStore.shadowRoot as ShadowRoot).addEventListener( + 'focusin', + updateFocus + ) + } + + function teardownPlugin() { + ;(coreStore.shadowRoot as ShadowRoot).removeEventListener( + 'pointerdown', + updateFocus + ) + ;(coreStore.shadowRoot as ShadowRoot).removeEventListener( + 'focusin', + updateFocus + ) + + reset() + + if (draw) { + coreStore.map.removeInteraction(draw) + draw = undefined + } + } + + function reset() { + route.value = [[], []] + currentlyFocusedInput.value = -1 + selectedPreference.value = 'recommended' + selectedTravelMode.value = 'driving-car' + selectedRouteTypesToAvoid.value = [] + routingResponseData.value = null + routeSource.clear() + + if (abortController) { + abortController.abort() + abortController = null + } + } + + function setRoute(index: number, remove = false) { + route.value = remove + ? route.value.toSpliced(index, 1) + : route.value.toSpliced(index, 0, []) + } + + return { + /** + * The coordinates selected by the user. + * If all coordinate pairs are filled, a route is requested. + */ + route, + + /** + * The response of the routing service depending on the {@link route} and + * other chosen options. + */ + routingResponseData, + + /** + * The input that currently has focus. + * Adds a draw interaction to the map if this value is not `-1` so the user + * can add a coordinate for the selected waypoint. + * + * @alpha + */ + currentlyFocusedInput, + + /** + * The preferences of the route type that a user can select. + * + * @alpha + */ + selectablePreferences, + + /** + * The types of routes that a user can select to avoid on their route. + * + * @alpha + */ + selectableRouteTypesToAvoid, + + /** + * The routing preference selected by the user. + * + * @alpha + */ + selectedPreference, + + /** + * The types of routes the user wishes to avoid on their route. + * + * @alpha + */ + selectedRouteTypesToAvoid, + + /** + * The selected mode of transportation by the user. + * + * @alpha + */ + selectedTravelMode, + + /** + * The modes of transportation a user can select. + * Is constrained by {@link RoutingPluginOptions.selectableTravelModes}. + * + * @alpha + */ + travelModes, + + /** + * Resets the state and clears the route layer source. + * + * @alpha + */ + reset, + + /** + * Inserts an empty coordinate pair into the route. + * + * @alpha + */ + setRoute, + + /** + * Value of {@link RoutingPluginOptions.displayPreferences}. + * + * @internal + */ + displayPreferences, + + /** + * Value of {@link RoutingPluginOptions.displayRouteTypesToAvoid}. + * + * @internal + */ + displayRouteTypesToAvoid, + + /** + * The feature of the {@link routingResponseData}. + * The ORS only returns one feature that is instead split in 1 to n segments. + * + * @internal + */ + routeFeature, + + /** + * Whether the route details should be displayed. + * Is `true` if {@link routingResponseData} is not `null`. + * + * @internal + */ + showDetails, + + /** @internal */ + setupPlugin, + + /** @internal */ + teardownPlugin, + } +}) + +if (import.meta.hot) { + import.meta.hot.accept(acceptHMRUpdate(useRoutingStore, import.meta.hot)) +} diff --git a/src/plugins/routing/types.ts b/src/plugins/routing/types.ts new file mode 100644 index 0000000000..baedbedf59 --- /dev/null +++ b/src/plugins/routing/types.ts @@ -0,0 +1,78 @@ +import type { + FeatureCollection, + LineString as GeoJsonLineString, +} from 'geojson' +import type { Ref } from 'vue' +import type { Icon, PluginOptions } from '@/core' + +export const PluginId = 'routing' + +export type SelectableTravelMode = + | 'driving-car' + | 'driving-hgv' + | 'cycling-regular' + | 'foot-walking' + | 'wheelchair' + +export interface TravelMode { + icon: Icon + label: Ref + value: SelectableTravelMode +} + +interface RouteStep { + distance: number + duration: number + instruction: string +} + +export interface RouteSegment { + distance: number + duration: number + steps: RouteStep[] +} + +export type RoutingResponseData = FeatureCollection< + GeoJsonLineString, + { segments: RouteSegment[] } +> + +export interface RoutingPluginOptions extends PluginOptions { + /** + * The type of routing service to be used. + * Currently, only the [OpenRouteService](https://openrouteservice.org/) (`'ors'`) is implemented. + */ + type: 'ors' + + /** + * The url of the routing service to be used. + */ + url: string + + /** + * The API key to access the routing service. + * Required for OpenRouteService if not already covered by the given {@link RoutingPluginOptions.url | `url`}. + */ + apiKey?: string + + /** + * Defines whether the user can choose their route preference. + * + * @defaultValue `false` + */ + displayPreferences?: boolean + + /** + * Defines whether the user can select types of routes to avoid. + * + * @defaultValue `false` + */ + displayRouteTypesToAvoid?: boolean + + /** + * List of available travel modes. + * + * @defaultValue `['driving-car', 'cycling-regular', 'foot-walking']` + */ + selectableTravelModes?: SelectableTravelMode[] +} diff --git a/src/plugins/routing/utils/handleErrors.ts b/src/plugins/routing/utils/handleErrors.ts new file mode 100644 index 0000000000..3c2b2dbdc3 --- /dev/null +++ b/src/plugins/routing/utils/handleErrors.ts @@ -0,0 +1,12 @@ +import { notifyUser } from '@/lib/notifyUser' + +export function handleErrors(error: unknown) { + let errorMessage = '' + if (error instanceof Error) { + errorMessage = error.message + console.error(error.message) + } else { + console.error('Unexpected error', error) + } + notifyUser('error', errorMessage) +} diff --git a/vue2/packages/lib/idx/CHANGELOG.md b/vue2/packages/lib/idx/CHANGELOG.md deleted file mode 100644 index 385b843bbc..0000000000 --- a/vue2/packages/lib/idx/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# CHANGELOG - -## 1.0.0 - -Initial release. diff --git a/vue2/packages/lib/idx/LICENSE b/vue2/packages/lib/idx/LICENSE deleted file mode 100644 index c29ce2f835..0000000000 --- a/vue2/packages/lib/idx/LICENSE +++ /dev/null @@ -1,287 +0,0 @@ - EUROPEAN UNION PUBLIC LICENCE v. 1.2 - EUPL © the European Union 2007, 2016 - -This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined -below) which is provided under the terms of this Licence. Any use of the Work, -other than as authorised under this Licence is prohibited (to the extent such -use is covered by a right of the copyright holder of the Work). - -The Work is provided under the terms of this Licence when the Licensor (as -defined below) has placed the following notice immediately following the -copyright notice for the Work: - - Licensed under the EUPL - -or has expressed by any other means his willingness to license under the EUPL. - -1. Definitions - -In this Licence, the following terms have the following meaning: - -- ‘The Licence’: this Licence. - -- ‘The Original Work’: the work or software distributed or communicated by the - Licensor under this Licence, available as Source Code and also as Executable - Code as the case may be. - -- ‘Derivative Works’: the works or software that could be created by the - Licensee, based upon the Original Work or modifications thereof. This Licence - does not define the extent of modification or dependence on the Original Work - required in order to classify a work as a Derivative Work; this extent is - determined by copyright law applicable in the country mentioned in Article 15. - -- ‘The Work’: the Original Work or its Derivative Works. - -- ‘The Source Code’: the human-readable form of the Work which is the most - convenient for people to study and modify. - -- ‘The Executable Code’: any code which has generally been compiled and which is - meant to be interpreted by a computer as a program. - -- ‘The Licensor’: the natural or legal person that distributes or communicates - the Work under the Licence. - -- ‘Contributor(s)’: any natural or legal person who modifies the Work under the - Licence, or otherwise contributes to the creation of a Derivative Work. - -- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of - the Work under the terms of the Licence. - -- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, - renting, distributing, communicating, transmitting, or otherwise making - available, online or offline, copies of the Work or providing access to its - essential functionalities at the disposal of any other natural or legal - person. - -2. Scope of the rights granted by the Licence - -The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, -sublicensable licence to do the following, for the duration of copyright vested -in the Original Work: - -- use the Work in any circumstance and for all usage, -- reproduce the Work, -- modify the Work, and make Derivative Works based upon the Work, -- communicate to the public, including the right to make available or display - the Work or copies thereof to the public and perform publicly, as the case may - be, the Work, -- distribute the Work or copies thereof, -- lend and rent the Work or copies thereof, -- sublicense rights in the Work or copies thereof. - -Those rights can be exercised on any media, supports and formats, whether now -known or later invented, as far as the applicable law permits so. - -In the countries where moral rights apply, the Licensor waives his right to -exercise his moral right to the extent allowed by law in order to make effective -the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to -any patents held by the Licensor, to the extent necessary to make use of the -rights granted on the Work under this Licence. - -3. Communication of the Source Code - -The Licensor may provide the Work either in its Source Code form, or as -Executable Code. If the Work is provided as Executable Code, the Licensor -provides in addition a machine-readable copy of the Source Code of the Work -along with each copy of the Work that the Licensor distributes or indicates, in -a notice following the copyright notice attached to the Work, a repository where -the Source Code is easily and freely accessible for as long as the Licensor -continues to distribute or communicate the Work. - -4. Limitations on copyright - -Nothing in this Licence is intended to deprive the Licensee of the benefits from -any exception or limitation to the exclusive rights of the rights owners in the -Work, of the exhaustion of those rights or of other applicable limitations -thereto. - -5. Obligations of the Licensee - -The grant of the rights mentioned above is subject to some restrictions and -obligations imposed on the Licensee. Those obligations are the following: - -Attribution right: The Licensee shall keep intact all copyright, patent or -trademarks notices and all notices that refer to the Licence and to the -disclaimer of warranties. The Licensee must include a copy of such notices and a -copy of the Licence with every copy of the Work he/she distributes or -communicates. The Licensee must cause any Derivative Work to carry prominent -notices stating that the Work has been modified and the date of modification. - -Copyleft clause: If the Licensee distributes or communicates copies of the -Original Works or Derivative Works, this Distribution or Communication will be -done under the terms of this Licence or of a later version of this Licence -unless the Original Work is expressly distributed only under this version of the -Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee -(becoming Licensor) cannot offer or impose any additional terms or conditions on -the Work or Derivative Work that alter or restrict the terms of the Licence. - -Compatibility clause: If the Licensee Distributes or Communicates Derivative -Works or copies thereof based upon both the Work and another work licensed under -a Compatible Licence, this Distribution or Communication can be done under the -terms of this Compatible Licence. For the sake of this clause, ‘Compatible -Licence’ refers to the licences listed in the appendix attached to this Licence. -Should the Licensee's obligations under the Compatible Licence conflict with -his/her obligations under this Licence, the obligations of the Compatible -Licence shall prevail. - -Provision of Source Code: When distributing or communicating copies of the Work, -the Licensee will provide a machine-readable copy of the Source Code or indicate -a repository where this Source will be easily and freely available for as long -as the Licensee continues to distribute or communicate the Work. - -Legal Protection: This Licence does not grant permission to use the trade names, -trademarks, service marks, or names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the copyright notice. - -6. Chain of Authorship - -The original Licensor warrants that the copyright in the Original Work granted -hereunder is owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each Contributor warrants that the copyright in the modifications he/she brings -to the Work are owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each time You accept the Licence, the original Licensor and subsequent -Contributors grant You a licence to their contributions to the Work, under the -terms of this Licence. - -7. Disclaimer of Warranty - -The Work is a work in progress, which is continuously improved by numerous -Contributors. It is not a finished work and may therefore contain defects or -‘bugs’ inherent to this type of development. - -For the above reason, the Work is provided under the Licence on an ‘as is’ basis -and without warranties of any kind concerning the Work, including without -limitation merchantability, fitness for a particular purpose, absence of defects -or errors, accuracy, non-infringement of intellectual property rights other than -copyright as stated in Article 6 of this Licence. - -This disclaimer of warranty is an essential part of the Licence and a condition -for the grant of any rights to the Work. - -8. Disclaimer of Liability - -Except in the cases of wilful misconduct or damages directly caused to natural -persons, the Licensor will in no event be liable for any direct or indirect, -material or moral, damages of any kind, arising out of the Licence or of the use -of the Work, including without limitation, damages for loss of goodwill, work -stoppage, computer failure or malfunction, loss of data or any commercial -damage, even if the Licensor has been advised of the possibility of such damage. -However, the Licensor will be liable under statutory product liability laws as -far such laws apply to the Work. - -9. Additional agreements - -While distributing the Work, You may choose to conclude an additional agreement, -defining obligations or services consistent with this Licence. However, if -accepting obligations, You may act only on your own behalf and on your sole -responsibility, not on behalf of the original Licensor or any other Contributor, -and only if You agree to indemnify, defend, and hold each Contributor harmless -for any liability incurred by, or claims asserted against such Contributor by -the fact You have accepted any warranty or additional liability. - -10. Acceptance of the Licence - -The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ -placed under the bottom of a window displaying the text of this Licence or by -affirming consent in any other similar way, in accordance with the rules of -applicable law. Clicking on that icon indicates your clear and irrevocable -acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and -conditions by exercising any rights granted to You by Article 2 of this Licence, -such as the use of the Work, the creation by You of a Derivative Work or the -Distribution or Communication by You of the Work or copies thereof. - -11. Information to the public - -In case of any Distribution or Communication of the Work by means of electronic -communication by You (for example, by offering to download the Work from a -remote location) the distribution channel or media (for example, a website) must -at least provide to the public the information requested by the applicable law -regarding the Licensor, the Licence and the way it may be accessible, concluded, -stored and reproduced by the Licensee. - -12. Termination of the Licence - -The Licence and the rights granted hereunder will terminate automatically upon -any breach by the Licensee of the terms of the Licence. - -Such a termination will not terminate the licences of any person who has -received the Work from the Licensee under the Licence, provided such persons -remain in full compliance with the Licence. - -13. Miscellaneous - -Without prejudice of Article 9 above, the Licence represents the complete -agreement between the Parties as to the Work. - -If any provision of the Licence is invalid or unenforceable under applicable -law, this will not affect the validity or enforceability of the Licence as a -whole. Such provision will be construed or reformed so as necessary to make it -valid and enforceable. - -The European Commission may publish other linguistic versions or new versions of -this Licence or updated versions of the Appendix, so far this is required and -reasonable, without reducing the scope of the rights granted by the Licence. New -versions of the Licence will be published with a unique version number. - -All linguistic versions of this Licence, approved by the European Commission, -have identical value. Parties can take advantage of the linguistic version of -their choice. - -14. Jurisdiction - -Without prejudice to specific agreement between parties, - -- any litigation resulting from the interpretation of this License, arising - between the European Union institutions, bodies, offices or agencies, as a - Licensor, and any Licensee, will be subject to the jurisdiction of the Court - of Justice of the European Union, as laid down in article 272 of the Treaty on - the Functioning of the European Union, - -- any litigation arising between other parties and resulting from the - interpretation of this License, will be subject to the exclusive jurisdiction - of the competent court where the Licensor resides or conducts its primary - business. - -15. Applicable Law - -Without prejudice to specific agreement between parties, - -- this Licence shall be governed by the law of the European Union Member State - where the Licensor has his seat, resides or has his registered office, - -- this licence shall be governed by Belgian law if the Licensor has no seat, - residence or registered office inside a European Union Member State. - -Appendix - -‘Compatible Licences’ according to Article 5 EUPL are: - -- GNU General Public License (GPL) v. 2, v. 3 -- GNU Affero General Public License (AGPL) v. 3 -- Open Software License (OSL) v. 2.1, v. 3.0 -- Eclipse Public License (EPL) v. 1.0 -- CeCILL v. 2.0, v. 2.1 -- Mozilla Public Licence (MPL) v. 2 -- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 -- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for - works other than software -- European Union Public Licence (EUPL) v. 1.1, v. 1.2 -- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong - Reciprocity (LiLiQ-R+). - -The European Commission may update this Appendix to later versions of the above -licences without producing a new version of the EUPL, as long as they provide -the rights granted in Article 2 of this Licence and protect the covered Source -Code from exclusive appropriation. - -All other changes or additions to this Appendix require the production of a new -EUPL version. \ No newline at end of file diff --git a/vue2/packages/lib/idx/README.md b/vue2/packages/lib/idx/README.md deleted file mode 100644 index 06d149239b..0000000000 --- a/vue2/packages/lib/idx/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# idx - -Helper function to traverse a nested object and return a certain property if the path can be traversed. diff --git a/vue2/packages/lib/idx/index.ts b/vue2/packages/lib/idx/index.ts deleted file mode 100644 index f904d62ec5..0000000000 --- a/vue2/packages/lib/idx/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -export const badPathSymbol = Symbol('Path could not be resolved.') - -/** - * Utility function (idx) for traversing the given path of the given object - * to retrieve data. - * Inspired by https://medium.com/javascript-inside/safely-accessing-deeply-nested-values-in-javascript-99bf72a0855a. - * - * @param object - The object to traverse. - * @param path - The path of keys / indices to traverse through the object. - * @returns The value(s) to be retrieved from the given object. - */ -export default (object: object, path: string[]): unknown | symbol => - path.reduce( - (acc, currentVal) => - acc && Object.prototype.hasOwnProperty.call(acc, currentVal) - ? acc[currentVal] - : badPathSymbol, - object - ) diff --git a/vue2/packages/lib/idx/package.json b/vue2/packages/lib/idx/package.json deleted file mode 100644 index f09102e0a3..0000000000 --- a/vue2/packages/lib/idx/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@polar/lib-idx", - "version": "1.0.0", - "description": "Provides a function to step into objects and fetch whatever.", - "keywords": ["OpenLayers", "ol", "POLAR", "lib", "getter"], - "license": "EUPL-1.2", - "type": "module", - "author": "Dataport AöR ", - "main": "index.ts", - "repository": { - "type": "git", - "url": "git+https://github.com/Dataport/polar.git", - "directory": "packages/lib/idx" - } -} diff --git a/vue2/packages/lib/idx/vite.config.js b/vue2/packages/lib/idx/vite.config.js deleted file mode 100644 index 0d2ec38a15..0000000000 --- a/vue2/packages/lib/idx/vite.config.js +++ /dev/null @@ -1,3 +0,0 @@ -import { getCodeConfig } from '../../../viteConfigs' - -export default getCodeConfig() diff --git a/vue2/packages/plugins/Routing/CHANGELOG.md b/vue2/packages/plugins/Routing/CHANGELOG.md deleted file mode 100644 index aeec3feade..0000000000 --- a/vue2/packages/plugins/Routing/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## 1.0.0 - -Initial release. diff --git a/vue2/packages/plugins/Routing/LICENSE b/vue2/packages/plugins/Routing/LICENSE deleted file mode 100644 index c29ce2f835..0000000000 --- a/vue2/packages/plugins/Routing/LICENSE +++ /dev/null @@ -1,287 +0,0 @@ - EUROPEAN UNION PUBLIC LICENCE v. 1.2 - EUPL © the European Union 2007, 2016 - -This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined -below) which is provided under the terms of this Licence. Any use of the Work, -other than as authorised under this Licence is prohibited (to the extent such -use is covered by a right of the copyright holder of the Work). - -The Work is provided under the terms of this Licence when the Licensor (as -defined below) has placed the following notice immediately following the -copyright notice for the Work: - - Licensed under the EUPL - -or has expressed by any other means his willingness to license under the EUPL. - -1. Definitions - -In this Licence, the following terms have the following meaning: - -- ‘The Licence’: this Licence. - -- ‘The Original Work’: the work or software distributed or communicated by the - Licensor under this Licence, available as Source Code and also as Executable - Code as the case may be. - -- ‘Derivative Works’: the works or software that could be created by the - Licensee, based upon the Original Work or modifications thereof. This Licence - does not define the extent of modification or dependence on the Original Work - required in order to classify a work as a Derivative Work; this extent is - determined by copyright law applicable in the country mentioned in Article 15. - -- ‘The Work’: the Original Work or its Derivative Works. - -- ‘The Source Code’: the human-readable form of the Work which is the most - convenient for people to study and modify. - -- ‘The Executable Code’: any code which has generally been compiled and which is - meant to be interpreted by a computer as a program. - -- ‘The Licensor’: the natural or legal person that distributes or communicates - the Work under the Licence. - -- ‘Contributor(s)’: any natural or legal person who modifies the Work under the - Licence, or otherwise contributes to the creation of a Derivative Work. - -- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of - the Work under the terms of the Licence. - -- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, - renting, distributing, communicating, transmitting, or otherwise making - available, online or offline, copies of the Work or providing access to its - essential functionalities at the disposal of any other natural or legal - person. - -2. Scope of the rights granted by the Licence - -The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, -sublicensable licence to do the following, for the duration of copyright vested -in the Original Work: - -- use the Work in any circumstance and for all usage, -- reproduce the Work, -- modify the Work, and make Derivative Works based upon the Work, -- communicate to the public, including the right to make available or display - the Work or copies thereof to the public and perform publicly, as the case may - be, the Work, -- distribute the Work or copies thereof, -- lend and rent the Work or copies thereof, -- sublicense rights in the Work or copies thereof. - -Those rights can be exercised on any media, supports and formats, whether now -known or later invented, as far as the applicable law permits so. - -In the countries where moral rights apply, the Licensor waives his right to -exercise his moral right to the extent allowed by law in order to make effective -the licence of the economic rights here above listed. - -The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to -any patents held by the Licensor, to the extent necessary to make use of the -rights granted on the Work under this Licence. - -3. Communication of the Source Code - -The Licensor may provide the Work either in its Source Code form, or as -Executable Code. If the Work is provided as Executable Code, the Licensor -provides in addition a machine-readable copy of the Source Code of the Work -along with each copy of the Work that the Licensor distributes or indicates, in -a notice following the copyright notice attached to the Work, a repository where -the Source Code is easily and freely accessible for as long as the Licensor -continues to distribute or communicate the Work. - -4. Limitations on copyright - -Nothing in this Licence is intended to deprive the Licensee of the benefits from -any exception or limitation to the exclusive rights of the rights owners in the -Work, of the exhaustion of those rights or of other applicable limitations -thereto. - -5. Obligations of the Licensee - -The grant of the rights mentioned above is subject to some restrictions and -obligations imposed on the Licensee. Those obligations are the following: - -Attribution right: The Licensee shall keep intact all copyright, patent or -trademarks notices and all notices that refer to the Licence and to the -disclaimer of warranties. The Licensee must include a copy of such notices and a -copy of the Licence with every copy of the Work he/she distributes or -communicates. The Licensee must cause any Derivative Work to carry prominent -notices stating that the Work has been modified and the date of modification. - -Copyleft clause: If the Licensee distributes or communicates copies of the -Original Works or Derivative Works, this Distribution or Communication will be -done under the terms of this Licence or of a later version of this Licence -unless the Original Work is expressly distributed only under this version of the -Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee -(becoming Licensor) cannot offer or impose any additional terms or conditions on -the Work or Derivative Work that alter or restrict the terms of the Licence. - -Compatibility clause: If the Licensee Distributes or Communicates Derivative -Works or copies thereof based upon both the Work and another work licensed under -a Compatible Licence, this Distribution or Communication can be done under the -terms of this Compatible Licence. For the sake of this clause, ‘Compatible -Licence’ refers to the licences listed in the appendix attached to this Licence. -Should the Licensee's obligations under the Compatible Licence conflict with -his/her obligations under this Licence, the obligations of the Compatible -Licence shall prevail. - -Provision of Source Code: When distributing or communicating copies of the Work, -the Licensee will provide a machine-readable copy of the Source Code or indicate -a repository where this Source will be easily and freely available for as long -as the Licensee continues to distribute or communicate the Work. - -Legal Protection: This Licence does not grant permission to use the trade names, -trademarks, service marks, or names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the copyright notice. - -6. Chain of Authorship - -The original Licensor warrants that the copyright in the Original Work granted -hereunder is owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each Contributor warrants that the copyright in the modifications he/she brings -to the Work are owned by him/her or licensed to him/her and that he/she has the -power and authority to grant the Licence. - -Each time You accept the Licence, the original Licensor and subsequent -Contributors grant You a licence to their contributions to the Work, under the -terms of this Licence. - -7. Disclaimer of Warranty - -The Work is a work in progress, which is continuously improved by numerous -Contributors. It is not a finished work and may therefore contain defects or -‘bugs’ inherent to this type of development. - -For the above reason, the Work is provided under the Licence on an ‘as is’ basis -and without warranties of any kind concerning the Work, including without -limitation merchantability, fitness for a particular purpose, absence of defects -or errors, accuracy, non-infringement of intellectual property rights other than -copyright as stated in Article 6 of this Licence. - -This disclaimer of warranty is an essential part of the Licence and a condition -for the grant of any rights to the Work. - -8. Disclaimer of Liability - -Except in the cases of wilful misconduct or damages directly caused to natural -persons, the Licensor will in no event be liable for any direct or indirect, -material or moral, damages of any kind, arising out of the Licence or of the use -of the Work, including without limitation, damages for loss of goodwill, work -stoppage, computer failure or malfunction, loss of data or any commercial -damage, even if the Licensor has been advised of the possibility of such damage. -However, the Licensor will be liable under statutory product liability laws as -far such laws apply to the Work. - -9. Additional agreements - -While distributing the Work, You may choose to conclude an additional agreement, -defining obligations or services consistent with this Licence. However, if -accepting obligations, You may act only on your own behalf and on your sole -responsibility, not on behalf of the original Licensor or any other Contributor, -and only if You agree to indemnify, defend, and hold each Contributor harmless -for any liability incurred by, or claims asserted against such Contributor by -the fact You have accepted any warranty or additional liability. - -10. Acceptance of the Licence - -The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ -placed under the bottom of a window displaying the text of this Licence or by -affirming consent in any other similar way, in accordance with the rules of -applicable law. Clicking on that icon indicates your clear and irrevocable -acceptance of this Licence and all of its terms and conditions. - -Similarly, you irrevocably accept this Licence and all of its terms and -conditions by exercising any rights granted to You by Article 2 of this Licence, -such as the use of the Work, the creation by You of a Derivative Work or the -Distribution or Communication by You of the Work or copies thereof. - -11. Information to the public - -In case of any Distribution or Communication of the Work by means of electronic -communication by You (for example, by offering to download the Work from a -remote location) the distribution channel or media (for example, a website) must -at least provide to the public the information requested by the applicable law -regarding the Licensor, the Licence and the way it may be accessible, concluded, -stored and reproduced by the Licensee. - -12. Termination of the Licence - -The Licence and the rights granted hereunder will terminate automatically upon -any breach by the Licensee of the terms of the Licence. - -Such a termination will not terminate the licences of any person who has -received the Work from the Licensee under the Licence, provided such persons -remain in full compliance with the Licence. - -13. Miscellaneous - -Without prejudice of Article 9 above, the Licence represents the complete -agreement between the Parties as to the Work. - -If any provision of the Licence is invalid or unenforceable under applicable -law, this will not affect the validity or enforceability of the Licence as a -whole. Such provision will be construed or reformed so as necessary to make it -valid and enforceable. - -The European Commission may publish other linguistic versions or new versions of -this Licence or updated versions of the Appendix, so far this is required and -reasonable, without reducing the scope of the rights granted by the Licence. New -versions of the Licence will be published with a unique version number. - -All linguistic versions of this Licence, approved by the European Commission, -have identical value. Parties can take advantage of the linguistic version of -their choice. - -14. Jurisdiction - -Without prejudice to specific agreement between parties, - -- any litigation resulting from the interpretation of this License, arising - between the European Union institutions, bodies, offices or agencies, as a - Licensor, and any Licensee, will be subject to the jurisdiction of the Court - of Justice of the European Union, as laid down in article 272 of the Treaty on - the Functioning of the European Union, - -- any litigation arising between other parties and resulting from the - interpretation of this License, will be subject to the exclusive jurisdiction - of the competent court where the Licensor resides or conducts its primary - business. - -15. Applicable Law - -Without prejudice to specific agreement between parties, - -- this Licence shall be governed by the law of the European Union Member State - where the Licensor has his seat, resides or has his registered office, - -- this licence shall be governed by Belgian law if the Licensor has no seat, - residence or registered office inside a European Union Member State. - -Appendix - -‘Compatible Licences’ according to Article 5 EUPL are: - -- GNU General Public License (GPL) v. 2, v. 3 -- GNU Affero General Public License (AGPL) v. 3 -- Open Software License (OSL) v. 2.1, v. 3.0 -- Eclipse Public License (EPL) v. 1.0 -- CeCILL v. 2.0, v. 2.1 -- Mozilla Public Licence (MPL) v. 2 -- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 -- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for - works other than software -- European Union Public Licence (EUPL) v. 1.1, v. 1.2 -- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong - Reciprocity (LiLiQ-R+). - -The European Commission may update this Appendix to later versions of the above -licences without producing a new version of the EUPL, as long as they provide -the rights granted in Article 2 of this Licence and protect the covered Source -Code from exclusive appropriation. - -All other changes or additions to this Appendix require the production of a new -EUPL version. \ No newline at end of file diff --git a/vue2/packages/plugins/Routing/README.md b/vue2/packages/plugins/Routing/README.md deleted file mode 100644 index 03ab90ee09..0000000000 --- a/vue2/packages/plugins/Routing/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Routing - -The Routing Plugin offers a routing functionality to the user. - -## Scope - -A user can select multiple waypoints by clicking on the map, which then are converted to an address, if a reverse geocoder is configured. -If at least two waypoints have been added, the route is automatically calculated and displayed on the map. - -The travel mode can be adjusted as well as the types of routes to avoid. -Similarly, the route preference is set to 'recommended' by default, but can be changed to 'fastest' or 'shortest'. - -Once a route is available, a detailed listing of every route segment is available including instructions, distance and duration. - -## Configuration - -### routing - -| fieldName | type | description | -| - | - | - | -| apiKey | string | The API key to access the routing service. Required for OpenRouteService. | -| format | 'geojson' | The format in which the answer of the routing service is expected in. The OpenRouteService also support `'json'` and `'gpx'`, which are currently not supported. | -| type | 'ors' | The type of routing service to be used. Currently, only the [OpenRouteService](https://openrouteservice.org/) (`'ors'`) is implemented. | -| url | string | The url of the routing service to be used. | -| displayPreferences | boolean? | Defines whether the user can choose their route preference. Defaults to `false`. | -| displayRouteTypesToAvoid | boolean? |Defines whether the user can select types of routes to avoid. Defaults to `false`. | -| selectableTravelModes | string[]? | List of available travel modes. Accepts `'driving-car'`, `'driving-hgv'`, `'cycling-regular'`, `'foot-walking'` and `'wheelchair'`. Defaults to `['driving-car', 'cycling-regular', 'foot-walking']`. | diff --git a/vue2/packages/plugins/Routing/package.json b/vue2/packages/plugins/Routing/package.json deleted file mode 100644 index 748d7f872f..0000000000 --- a/vue2/packages/plugins/Routing/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@polar/plugin-routing", - "version": "1.0.0", - "description": "Routing plugin for POLAR that adds routing UI for routing services to the client.", - "keywords": [ - "OpenLayers", - "ol", - "POLAR", - "plugin", - "routing", - "ors", - "OpenRouteService" - ], - "license": "EUPL-1.2", - "type": "module", - "author": "Dataport AöR ", - "main": "src/index.ts", - "repository": { - "type": "git", - "url": "https://github.com/Dataport/polar.git", - "directory": "packages/plugins/Routing" - }, - "files": [ - "src/**/*", - "CHANGELOG.md" - ], - "peerDependencies": { - "@repositoryname/vuex-generators": "^1.1.2", - "ol": "^10.3.1", - "vue": "^2.6.14", - "vuex": "^3.6.2" - }, - "devDependencies": { - "@polar/lib-custom-types": "^2.2.0", - "@polar/lib-idx": "^1.0.0", - "@polar/lib-passes-boundary-check": "^2.0.0", - "@polar/lib-test-mount-parameters": "^1.4.0" - } -} diff --git a/vue2/packages/plugins/Routing/src/components/Routing.vue b/vue2/packages/plugins/Routing/src/components/Routing.vue deleted file mode 100644 index e11688d9ff..0000000000 --- a/vue2/packages/plugins/Routing/src/components/Routing.vue +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - diff --git a/vue2/packages/plugins/Routing/src/components/RoutingDetails.vue b/vue2/packages/plugins/Routing/src/components/RoutingDetails.vue deleted file mode 100644 index c0570bf54a..0000000000 --- a/vue2/packages/plugins/Routing/src/components/RoutingDetails.vue +++ /dev/null @@ -1,78 +0,0 @@ - - - - - diff --git a/vue2/packages/plugins/Routing/src/components/RoutingOptions.vue b/vue2/packages/plugins/Routing/src/components/RoutingOptions.vue deleted file mode 100644 index d91ba9929b..0000000000 --- a/vue2/packages/plugins/Routing/src/components/RoutingOptions.vue +++ /dev/null @@ -1,188 +0,0 @@ - - - - - diff --git a/vue2/packages/plugins/Routing/src/components/index.ts b/vue2/packages/plugins/Routing/src/components/index.ts deleted file mode 100644 index 0ae0332019..0000000000 --- a/vue2/packages/plugins/Routing/src/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Routing } from './Routing.vue' diff --git a/vue2/packages/plugins/Routing/src/index.ts b/vue2/packages/plugins/Routing/src/index.ts deleted file mode 100644 index 39969b1371..0000000000 --- a/vue2/packages/plugins/Routing/src/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Vue from 'vue' -import { RoutingConfiguration } from '@polar/lib-custom-types' -import { makeStoreModule } from './store' -import { Routing } from './components' -import locales from './locales' - -/** - * A function that dispatches an action to add the routing component to the Vuex store. - * - * This function returns another function that accepts a Vue instance. It dispatches the - * 'addComponent' action to the store with relevant configuration options such as the - * routing plugin, language, and the store module. - * - * @param options - Configuration options for the routing setup, including language and other routing-related settings. - * @returns A function that accepts a Vue instance and dispatches the 'addComponent' action to the Vuex store. - */ -export default (options: RoutingConfiguration) => (instance: Vue) => { - return instance.$store.dispatch('addComponent', { - name: 'routing', - plugin: Routing, - locales, - storeModule: makeStoreModule(), - options, - }) -} diff --git a/vue2/packages/plugins/Routing/src/locales.ts b/vue2/packages/plugins/Routing/src/locales.ts deleted file mode 100644 index eba0f9b727..0000000000 --- a/vue2/packages/plugins/Routing/src/locales.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Locale } from '@polar/lib-custom-types' - -export const resourcesDe = { - plugins: { - routing: { - title: 'Routenplaner', - button: { - closeTitle: 'Routenplanung schließen', - openTitle: 'Routenplanung öffnen', - }, - label: { - aria: 'Durch Klicken in die Karte eine Koordinate als {{position}} auswählen.', - add: 'Wegpunkt hinzufügen', - remove: 'Wegpunkt entfernen', - start: 'Startadresse', - middle: 'Wegpunkt', - end: 'Zieladresse', - mode: 'Fortbewegungsart', - preference: 'Bevorzugte Route', - }, - inputHint: - 'Wählen Sie durch Klicken einen Punkt auf der Karte aus oder geben Sie eine Adresse ein.', - resetButton: 'Zurücksetzen', - travelMode: { - car: 'Auto', - hgv: 'LKW', - bike: 'Fahrrad', - walking: 'Zu Fuß', - wheelchair: 'Rollstuhl', - }, - preference: { - recommended: 'Empfohlen', - fastest: 'Schnellste', - shortest: 'Kürzeste', - }, - avoidRoutesTitle: 'Verkehrswege meiden', - avoidRoutes: { - highways: 'Autobahnen', - tollways: 'Mautstraßen', - ferries: 'Fähren', - }, - sendRequestButton: 'Absenden', - routeDetails: 'Details zur Route', - distance: 'Entfernung:', - duration: 'Dauer:', - }, - }, -} - -export const resourcesEn = { - plugins: { - routing: { - title: 'Route Planner', - button: { - closeTitle: 'Hide routing tool', - openTitle: 'Show rooting tool', - }, - label: { - aria: 'Add a coordinate as {{position}} by clicking in the map.', - add: 'Add waypoint', - remove: 'Remove waypoint', - start: 'Start Address', - middle: 'Waypoint', - end: 'Destination Address', - mode: 'Travel Mode', - preference: 'Preferred Route', - }, - inputHint: 'Click the map to choose a point or enter an Ad', - resetButton: 'Reset', - travelMode: { - car: 'Car', - hgv: 'Heavy Goods Vehicle', - bike: 'Bike', - walking: 'Walking', - wheelchair: 'Wheelchair', - }, - preference: { - recommended: 'Recommended', - fastest: 'Fastest', - shortest: 'Shortest', - }, - avoidRoutesTitle: 'Types of routes to avoid', - avoidRoutes: { - highways: 'Highways', - tollways: 'Tollways', - ferries: 'Ferries', - }, - sendRequestButton: 'Send', - routeDetails: 'Route Details', - distance: 'Distance:', - duration: 'Duration:', - }, - }, -} - -const locales: Locale[] = [ - { - type: 'de', - resources: resourcesDe, - }, - { - type: 'en', - resources: resourcesEn, - }, -] - -export default locales diff --git a/vue2/packages/plugins/Routing/src/store/actions.ts b/vue2/packages/plugins/Routing/src/store/actions.ts index 78ed5438fe..54b2f49dbe 100644 --- a/vue2/packages/plugins/Routing/src/store/actions.ts +++ b/vue2/packages/plugins/Routing/src/store/actions.ts @@ -1,57 +1,9 @@ import { type PolarActionTree } from '@polar/lib-custom-types' -import Feature from 'ol/Feature' -import { LineString, Point } from 'ol/geom' -import Draw from 'ol/interaction/Draw' -import VectorLayer from 'ol/layer/Vector' -import { transform } from 'ol/proj' -import VectorSource from 'ol/source/Vector' -import { Stroke, Style } from 'ol/style' import { RoutingState, RoutingGetters } from '../types' -import { fetchRoutingDirections } from '../utils/routingServiceUtils' - -const routeSource = new VectorSource() -let routeLayer -let draw: Draw const actions: PolarActionTree = { - /** - * Initializes the tool by updating the state from mapConfig and by setting up the draw layer and click event listener. - */ - setupModule({ rootGetters, dispatch }) { - routeLayer = new VectorLayer({ - source: routeSource, - style: new Style({ - stroke: new Stroke({ color: 'blue', width: 6 }), - }), - }) - rootGetters.map.addLayer(routeLayer) - - dispatch('initializeDraw') - }, - initializeDraw({ commit }) { - draw = new Draw({ stopClick: true, type: 'Point' }) - // @ts-expect-error | internal hack to detect it in @polar/plugin-pins and @polar/plugin-gfi - draw._isRoutingDraw = true - draw.on('drawend', (e) => { - commit( - 'addCoordinateToRoute', - (e.feature.getGeometry() as Point).getCoordinates() - ) - // @ts-expect-error | internal hack to detect it in @polar/plugin-pins and @polar/plugin-gfi - draw._isRoutingDraw = false - }) - }, - setCurrentlyFocusedInput({ commit, getters, rootGetters }, index: number) { - const previousIndex = getters.currentlyFocusedInput - commit('setCurrentlyFocusedInput', index) - if (previousIndex === -1 && index !== -1) { - rootGetters.map.addInteraction(draw) - } else if (previousIndex !== -1 && index === -1) { - rootGetters.map.removeInteraction(draw) - } - }, - // TODO: Add implementation for the search functionality - /* async search({ commit, dispatch, getters, rootGetters }, input: string) { + // TODO: Add implementation for the search functionality + /* async search({ commit, dispatch, getters, rootGetters }, input: string) { if (getters.searchConfiguration) { searchConfiguration: { availability: 'plugin/addressSearch/featuresAvailable', @@ -69,76 +21,6 @@ const actions: PolarActionTree = { } } }, */ - handleErrors({ dispatch }, error) { - let errorMessage = '' - if (error instanceof Error) { - errorMessage = error.message - console.error(error.message) - } else { - console.error('Unexpected error', error) - } - dispatch( - 'plugin/toast/addToast', - { - type: 'error', - text: errorMessage, - }, - { root: true } - ) - }, - /** - * Sends a routing request to the configured service. - */ - async getRoute({ commit, dispatch, state, getters }) { - dispatch('clearRoute') - try { - const response = await fetchRoutingDirections( - getters.url, - getters.routeAsWGS84, - state.selectedRouteTypesToAvoid, - state.selectedPreference, - getters.configuration.apiKey - ) - const data = await response.json() - commit('setRoutingResponseData', data) - dispatch('drawRoute') - } catch (error) { - dispatch('handleErrors', error) - } - }, - /** - * Draws the calculated route on the map. - */ - drawRoute({ getters }) { - const transformedCoordinates = - getters.routingResponseData.features[0].geometry.coordinates.map( - (coordinate) => transform(coordinate, 'EPSG:4326', 'EPSG:25832') - ) - const routeLineString = new LineString(transformedCoordinates) - - const routeFeature = new Feature({ - geometry: routeLineString, - }) - routeSource.addFeature(routeFeature) - }, - /** - * Deletes the current route drawing from the map. - */ - clearRoute() { - routeSource.clear() - }, - /** - * Resets the selected coordinates and routing settings. - */ - reset({ commit, dispatch }) { - commit('resetRoute') - commit('setCurrentlyFocusedInput', -1) - commit('setSelectedTravelMode', 'driving-car') - commit('setSelectedPreference', 'recommended') - commit('setSelectedRouteTypesToAvoid', []) - commit('setRoutingResponseData', {}) - dispatch('clearRoute') - }, } export default actions diff --git a/vue2/packages/plugins/Routing/src/store/index.ts b/vue2/packages/plugins/Routing/src/store/index.ts deleted file mode 100644 index bb517013da..0000000000 --- a/vue2/packages/plugins/Routing/src/store/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { type PolarModule } from '@polar/lib-custom-types' -import { - generateSimpleGetters, - generateSimpleMutations, -} from '@repositoryname/vuex-generators' -import { type Coordinate } from 'ol/coordinate' -import { RoutingGetters, RoutingState } from '../types' -import { transformCoordinateToWGS84 } from '../utils/routingServiceUtils' -import { getInitialState } from './state' -import actions from './actions' - -interface SetRoutePayload { - index: number - remove?: boolean -} - -/** - * Creates and returns a Vuex store module with namespacing enabled. - * - * The module is initialized with a predefined state, actions, getters, and mutations. - * - * @returns A Vuex store module configured with state, actions, getters, and mutations. - */ -export const makeStoreModule = (): PolarModule< - RoutingState, - RoutingGetters -> => ({ - namespaced: true, - state: getInitialState(), - actions, - getters: { - ...generateSimpleGetters(getInitialState()), - configuration: (_, __, ___, rootGetters) => - rootGetters.configuration.routing, - displayPreferences: (_, { configuration }) => - configuration.displayPreferences || false, - displayRouteTypesToAvoid: (_, { configuration }) => - configuration.displayRouteTypesToAvoid || false, - routeAsWGS84: (_, getters, __, rootGetters) => - getters.route.map((coordinate) => - transformCoordinateToWGS84( - coordinate, - rootGetters.map.getView().getProjection().getCode() - ) - ), - /* searchConfiguration: (_, getters) => - getters.configuration.searchConfiguration || null, */ - selectableTravelModes: (_, { configuration }) => - configuration.selectableTravelModes || [ - 'driving-car', - 'cycling-regular', - 'foot-walking', - ], - url: (_, getters) => - getters.configuration.url + - getters.selectedTravelMode + - '/' + - getters.configuration.format, - }, - mutations: { - ...generateSimpleMutations(getInitialState()), - addCoordinateToRoute(state, coordinate: Coordinate) { - const currentRoute = [...state.route] - currentRoute[state.currentlyFocusedInput] = coordinate - state.route = currentRoute - }, - resetRoute(state) { - state.route = [[], []] - }, - setRoute(state, { index, remove }: SetRoutePayload) { - if (remove) { - state.route = state.route.toSpliced(index, 1) - return - } - state.route = state.route.toSpliced(index, 0, []) - }, - updateShowSteps(state) { - state.showSteps = !state.showSteps - }, - }, -}) diff --git a/vue2/packages/plugins/Routing/src/store/state.ts b/vue2/packages/plugins/Routing/src/store/state.ts deleted file mode 100644 index 6cdc7bc210..0000000000 --- a/vue2/packages/plugins/Routing/src/store/state.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { FeatureCollection, LineString } from 'geojson' -import { RoutingState } from '../types' - -export const getInitialState = (): RoutingState => ({ - currentlyFocusedInput: -1, - route: [[], []], - routingResponseData: {} as FeatureCollection, - selectableRouteTypesToAvoid: [ - { - key: 'highways', - locale: 'plugins.routing.avoidRoutes.highways', - }, - { - key: 'tollways', - locale: 'plugins.routing.avoidRoutes.tollways', - }, - { - key: 'ferries', - locale: 'plugins.routing.avoidRoutes.ferries', - }, - ], - selectedPreference: 'recommended', - selectedRouteTypesToAvoid: [], - selectedTravelMode: 'driving-car', - showSteps: false, -}) diff --git a/vue2/packages/plugins/Routing/src/types.ts b/vue2/packages/plugins/Routing/src/types.ts deleted file mode 100644 index e944465e6d..0000000000 --- a/vue2/packages/plugins/Routing/src/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { - RoutingConfiguration, - SelectableTravelMode, -} from '@polar/lib-custom-types' -import { type Coordinate } from 'ol/coordinate' -import { FeatureCollection, LineString } from 'geojson' - -type SelectablePreference = 'recommended' | 'fastest' | 'shortest' - -interface Selectable { - key: string - locale: string -} - -export interface RoutingState { - currentlyFocusedInput: number - route: Coordinate[] - routingResponseData: FeatureCollection - selectableRouteTypesToAvoid: Selectable[] - selectedPreference: SelectablePreference - selectedRouteTypesToAvoid: string[] - selectedTravelMode: SelectableTravelMode - showSteps: boolean -} - -export interface RoutingGetters extends RoutingState { - configuration: RoutingConfiguration - displayPreferences: boolean - displayRouteTypesToAvoid: boolean - routeAsWGS84: Coordinate[] - selectableTravelModes: SelectableTravelMode[] - url: string -} diff --git a/vue2/packages/plugins/Routing/src/utils/routingServiceUtils.ts b/vue2/packages/plugins/Routing/src/utils/routingServiceUtils.ts deleted file mode 100644 index 0fc11182d2..0000000000 --- a/vue2/packages/plugins/Routing/src/utils/routingServiceUtils.ts +++ /dev/null @@ -1,55 +0,0 @@ -import i18next from 'i18next' -import { transform } from 'ol/proj' - -async function fetchRoutingDirections( - url: string, - searchCoordinates: number[][], - selectedRouteTypesToAvoid: string[], - selectedPreference: string, - apiKey: string -) { - const response = await fetch(url, { - method: 'POST', - headers: { - /* eslint-disable @typescript-eslint/naming-convention */ - 'Content-Type': 'application/json', - Authorization: apiKey, - /* eslint-enable @typescript-eslint/naming-convention */ - }, - body: JSON.stringify({ - coordinates: searchCoordinates, - geometry: true, - instructions: true, - language: i18next.language, - options: { - avoid_features: selectedRouteTypesToAvoid, - }, - preference: selectedPreference, - units: 'm', - }), - }) - if (!response.ok) { - throw new Error('Route could not be determined. Try different coordinates.') - } - return response -} - -/** - * Transforms a coordinate from a given EPSG system to WGS84 (EPSG:4326). - * - * @param coordinate - The coordinate to be transformed. - * @param sourceEpsg - The source EPSG code (e.g., "EPSG:3857"). - * @returns The transformed coordinate in WGS84 format. - */ -function transformCoordinateToWGS84( - coordinate: number[], - sourceEpsg: string -): number[] { - if (!sourceEpsg) { - throw new Error('Source EPSG code is required') - } - - return transform(coordinate, sourceEpsg, 'EPSG:4326') -} - -export { fetchRoutingDirections, transformCoordinateToWGS84 } diff --git a/vue2/packages/plugins/Routing/vite.config.js b/vue2/packages/plugins/Routing/vite.config.js deleted file mode 100644 index 0d2ec38a15..0000000000 --- a/vue2/packages/plugins/Routing/vite.config.js +++ /dev/null @@ -1,3 +0,0 @@ -import { getCodeConfig } from '../../../viteConfigs' - -export default getCodeConfig() diff --git a/vue2/packages/types/custom/core.ts b/vue2/packages/types/custom/core.ts index 40b43279a1..13a08c2d53 100644 --- a/vue2/packages/types/custom/core.ts +++ b/vue2/packages/types/custom/core.ts @@ -319,23 +319,6 @@ export interface ReverseGeocoderConfiguration { zoomTo?: number } -export type SelectableTravelMode = - | 'driving-car' - | 'driving-hgv' - | 'cycling-regular' - | 'foot-walking' - | 'wheelchair' - -export interface RoutingConfiguration { - apiKey: string - format: 'geojson' - type: 'ors' - url: string - displayPreferences?: boolean - displayRouteTypesToAvoid?: boolean - selectableTravelModes?: SelectableTravelMode[] -} - /** Style of a toast */ export interface ToastStyle { /** Color of the toast. */ @@ -394,7 +377,6 @@ export interface MapConfig extends MasterportalApiConfig { legend?: LegendConfiguration pins?: PinsConfiguration reverseGeocoder?: ReverseGeocoderConfiguration - routing?: RoutingConfiguration scale?: ScaleConfiguration toast?: ToastConfiguration zoom?: ZoomConfiguration @@ -434,8 +416,10 @@ export interface CoreState { zoomLevel: number } -export interface CoreGetters - extends Omit { +export interface CoreGetters extends Omit< + CoreState, + 'components' | 'hovered' | 'map' | 'selected' +> { // omitted from CoreState as actual getter type diverges components: PluginContainer[] hovered: Feature | null