Skip to content
2 changes: 1 addition & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Info from '@/fragments/dialogs/info/Info'
import MainMenu from '@/common/main-menu'
import utils from '@/support/utils'
import {EventBus} from '@/common/event-bus'
import CitySelector from '@/fragments/city-selector/CitySelector.vue';
import CitySelector from '@/fragments/city-selector/CitySelector.vue'


export default {
Expand Down
1 change: 1 addition & 0 deletions src/config-examples/app-config-example.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const appConfig = {
setCustomMenuIcons: true, // If the icons of the menu loaded must be customized via (only necessary if useORSMenu is true)
baseMenuExternalUrl: 'https://openrouteservice.org' // The base url to retrieve the menu items
},
defaultCountry: 'germany',
defaultState: 'baden-wuerttemberg',
defaultCity: 'heidelberg',
defaultLocale: 'de-de', // only set as default a locale that is present in the app. By default, they are: 'en-us', 'de-de' and 'pt-br'
Expand Down
8 changes: 8 additions & 0 deletions src/fragments/city-selector/CitySelector.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
<template>
<div class="container">
<v-select
:label="$t('citySelector.country')"
:items="countryOptions"
item-text="text"
item-value="value"
v-model="selectedCountry"
/>
<v-select
:label="$t('citySelector.state')"
:items="states"
item-text="text"
item-value="value"
v-model="selectedState"
:disabled="!selectedCountry"
/>
<v-select
:label="$t('citySelector.city')"
Expand Down
63 changes: 45 additions & 18 deletions src/fragments/city-selector/city-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,79 @@ export default {
}

return {
selectedCountry: urlParams.get('country') || appConfig.defaultCountry,
selectedState: urlParams.get('state') || appConfig.defaultState,
selectedCity: urlParams.get('city') || appConfig.defaultCity,
aois: {}
countries: {}
}
},

async created() {
try {
const res = await fetch(`/aois/index.json`)
this.aois = await res.json()
const res = await fetch('/aois/countries.json')
this.countries = await res.json()
} catch (e) {
console.error('Failed to load AOIs:', e)
console.error('Failed to load countries:', e)
}
},

computed: {
stateCityMap() {
countryStateCityMap() {
const map = {}

Object.entries(this.aois).forEach(([rawState, cities]) => {
map[rawState] = {
text: this.prepareString(rawState),
value: rawState,
cities: cities.map(rawCity => ({
text: this.prepareString(rawCity),
value: rawCity
}))
Object.entries(this.countries).forEach(([rawCountry, states]) => {
const stateMap = {}

Object.entries(states).forEach(([rawState, cities]) => {
stateMap[rawState] = {
text: this.prepareString(rawState),
value: rawState,
cities: cities.map(rawCity => ({
text: this.prepareString(rawCity),
value: rawCity
}))
}
})

map[rawCountry] = {
text: this.prepareString(rawCountry),
value: rawCountry,
states: stateMap
}
})

return map
},

countryOptions() {
return Object.values(this.countryStateCityMap)
.sort((a, b) => a.text.localeCompare(b.text))
},

states() {
return Object.values(this.stateCityMap)
if (!this.selectedCountry) return []
return Object.values(this.countryStateCityMap[this.selectedCountry]?.states || {})
.sort((a, b) => a.text.localeCompare(b.text))
},

cities() {
if (!this.selectedState) return []
return (this.stateCityMap[this.selectedState]?.cities || [])
if (!this.selectedCountry || !this.selectedState) return []
return (this.countryStateCityMap[this.selectedCountry]?.states[this.selectedState]?.cities || [])
.sort((a, b) => a.text.localeCompare(b.text))
}
},
watch: {
selectedCountry(newCountry) {
const states = Object.values(this.countryStateCityMap[newCountry]?.states || {})
if (states.length === 1) {
this.selectedState = states[0].value
} else {
this.selectedState = null
this.selectedCity = null
}
},
selectedState(newState) {
const cities = this.stateCityMap[newState]?.cities || []
const cities = this.countryStateCityMap[this.selectedCountry]?.states[newState]?.cities || []
if (cities.length === 1) {
this.selectedCity = cities[0].value
this.changeCity()
Expand All @@ -79,14 +105,15 @@ export default {
this.$router.push({
name: 'MapLocation',
query: {
country: this.selectedCountry,
state: this.selectedState,
city: this.selectedCity,
}
})

EventBus.$emit(
'city-change',
this.selectedState + '/' + this.selectedCity
this.selectedCountry + '/' + this.selectedState + '/' + this.selectedCity
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

export default {
citySelector: {
country: 'Land',
state: 'Bundesland',
city: 'Stadt'
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

export default {
citySelector: {
country: 'Country',
state: 'State',
city: 'City'
}
Expand Down
3 changes: 2 additions & 1 deletion src/support/map-data-services/ors-params-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
if (url.length > 1) {
urlParams = new URLSearchParams(url[1])
}
const country = urlParams.get('country') || appConfig.defaultCountry
const state = urlParams.get('state') || appConfig.defaultState
const city = urlParams.get('city') || appConfig.defaultCity
fetch(`/aois/${state}/${city}.geojson`)
fetch(`/aois/${country}/${state}/${city}.geojson`)

Check failure on line 32 in src/support/map-data-services/ors-params-parser.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Ensure that tainted data is validated before being used to construct a client-side request URL.

See more on https://sonarcloud.io/project/issues?id=GIScience_ors-map-client&issues=AZ7dRLu9L49KgC-o0IKJ&open=AZ7dRLu9L49KgC-o0IKJ&pullRequest=492
.then(result => result.json())
.then(json => {
region_bbox = Leaflet.geoJSON(json).getBounds()
Expand Down
Loading