Newer
Older
<v-app>
<v-app-bar class="px-6"
><strong class="site-title">OSM Place Search Logger</strong>
<v-spacer></v-spacer>
<a href="https://wiki.openstreetmap.org/wiki/OSM_Place_Search_Logger">About</a>
</v-app-bar>
<v-main fill-height>
<v-container fluid class="fill-height primary">
<v-row class="fill-height">
<v-col cols="6">
<v-card class="px-1 overflow-y-auto" flat>
<v-toolbar dense floating flat>
<v-text-field
ref="searchField"
hide-details
single-line
variant="outlined"
v-model="search"
label="Search"
v-on:keyup.enter="onEnter"
clearable
></v-text-field>
<v-btn icon @click="onSearchClick">
<v-icon>mdi-magnify</v-icon>
</v-btn>
</v-toolbar>
This web application stores your search queries in anonymised form and is used for
educational and research purposes in order to improve the awesome OpenStreetMap project. By
using this web application you agree with these conditions.
</v-card>
<div style="max-height: 70vh; overflow-y: auto">
<result-table
:result-list="listItems"
:on-submit-solution="submitSolution"
:on-select-option="onSelection"
></result-table>
<div class="no-entries-label" v-if="searchedWithoutResults">
No entries found
</div>
<div v-if="searchedWithoutResults || listItems.length !== 0" width="100%"
class="d-flex flex-row my-6 align-center flex-wrap" style="gap: 10px">
<v-text-field
hide-details
density="compact"
placeholder="Any other comments?"
v-model="comment"
></v-text-field>
<v-btn :disabled="!selected" @click="submitSolution" class="selected-button">
Submit Solution
</v-btn>
<v-btn @click="noSolutionFound" class="bg-red-lighten-4"
>Entry not present
</v-btn>
<leaflet-map :poi="selectedGeoJson" @on-b-box-changed="onBBoxChanged"></leaflet-map>
</v-col>
</v-row>
</v-container>
</v-main>
</v-app>
import {ref, computed, onMounted} from 'vue'
import type GeoJsonSearchResult from './types/geojson-search-result'
import LeafletMap from './LeafletMap.vue'
import ResultTable from './ResultTable.vue'
import Feature from './types/feature'
import BoundingBox from "./types/BoundingBox";
const sessionId = ref<string>()
const userId = ref<string>()
const rawSearchResult = ref<GeoJsonSearchResult>()
const boundingBox = ref<BoundingBox>()
const bBoxWhenSearched = ref<BoundingBox>()
searchField.value?.blur()
onSearchClick()
function onBBoxChanged(bbox) {
boundingBox.value = bbox // this step might be unnecessary -> check if this is only a reference to the object from
// LeafletMap.vue. if so, we don't need to constantly reassign this value
const viewbox = computed(() => {
return `${boundingBox.value.lonNE},${boundingBox.value.latNE},${boundingBox.value.lonSW},${boundingBox.value.latSW}`
})
const backendBaseUrl = 'https://osm-place-search-logger.infs.ch/api'
// const backendBaseUrl = 'http://localhost:8080/api'
let body = {
userId: userId.value,
sessionId: sessionId.value,
search: search.value,
rawSearchResult: rawSearchResult.value,
selection: result,
success: true,
}
if (comment.value !== '') {
body = {...body, comment: comment.value}
}
fetch(`${backendBaseUrl}/submit`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
let body = {
userId: userId.value,
sessionId: sessionId.value,
search: search.value,
rawSearchResult: rawSearchResult.value,
success: false,
}
if (comment.value !== '') {
body = {...body, comment: comment.value}
}
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}).then(reset)
}
function reset() {
rawSearchResult.value = undefined
search.value = ''
sessionId.value = crypto.randomUUID()
}
function getResults() {
bBoxWhenSearched.value = {...boundingBox.value}
selected.value = null;
const query = queryString.value;
const requestString = `${baseUrl}?q=${query}&format=geojson&limit=20&viewbox=${viewbox.value}`;
fetch(requestString, {method: 'GET'})
.then((res) => res.json())
.then((json) => (rawSearchResult.value = json))
.then(() =>
fetch(`${backendBaseUrl}/search`, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
userId: userId.value,
sessionId: sessionId.value,
search: search.value,
rawSearchResult: rawSearchResult.value,
})
})
)
//.catch((err) => (error.value = err))
sessionId.value = crypto.randomUUID()
userId.value = crypto.randomUUID()
const query = search.value ? search.value : ''
const encodedValue = encodeURIComponent(query)
return encodedValue.replaceAll('%20', '+')
return rawSearchResult.value?.features || ([] as Feature[])
if (selected.value === null) {
return {...rawSearchResult.value, features: []}
}
return {...rawSearchResult.value, features: [selected.value]}
const searchedWithoutResults = computed(() => {
return rawSearchResult.value && listItems.value.length === 0
})
// https://nominatim.openstreetmap.org/search.php?q=oberer+gubel+48+jona&format=jsonv2
</script>
<style scoped lang="scss">
Ciro Brodmann
committed
.v-app-bar a {
Ciro Brodmann
committed
}
.no-entries-label {
font-weight: 500;
font-size: 12pt;
color: #717171;
text-align: center;
margin: 20px 0;
}
background: #7d92f5 !important;
color: white;
&.v-btn--disabled {
background-color: lighten(#7d92f5, 20) !important;
}