Mercurial > gemma
view client/src/application/Topbar.vue @ 1119:6d4cc4389c8f store-refactoring
merged default into store-refactoring
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Tue, 06 Nov 2018 09:12:05 +0100 |
parents | 595654ad3f66 ef7c102497b8 |
children | d9e6a1f6f394 |
line wrap: on
line source
<template> <div class="topbar d-flex flex-row"> <div @click="toggleSidebar"> <i class="ui-element menubutton d-print-none fa fa-bars"></i> </div> <div v-if="routeName == 'mainview'" :class="searchbarContainerStyle"> <div class="input-group-prepend shadow"> <span @click="toggleSearchbar" class="ui-element input-group-text searchlabel d-print-none" for="search"> <i class="fa fa-search d-print-none"></i> </span> </div> <div class="searchgroup"> <input @keyup.enter="takeFirstSearchresult" v-if="!searchbarCollapsed" id="search" v-model="searchQuery" type="text" class="form-control ui-element search searchbar d-print-none"> <ul v-if="!searchbarCollapsed && searchResults !== null " class="list-group d-print-none"> <li v-for="entry of searchResults" :key="entry.name" class="list-group-item"> <a href="#" @click.prevent="moveToSearchResult(entry)">{{entry.name}}</a> </li> </ul> </div> </div> <div v-if="routeName == 'mainview' && Object.keys(currentProfile).length" class="splitbutton"> <i @click="splitScreen" class="ui-element splitscreen fa fa-window-restore shadow"></i> </div> <div class=""> <Layers v-if="routeName == 'mainview'"></Layers> </div> <div class=""> <Identify v-if="routeName == 'mainview'"></Identify> </div> </div> </template> <style lang="scss"> .searchgroup { width: 90%; } .splitbutton { height: $icon-height; } .list-group { pointer-events: auto; } .splitscreen { background-color: white; padding: $small-offset; margin-right: $small-offset; margin-left: $offset; border-radius: $border-radius; height: $icon-height; width: $icon-width; } .menubutton { background-color: white; padding: $small-offset; border-radius: $border-radius; margin-left: $offset; height: $icon-height; width: $icon-width; } .searchcontainer { height: $icon-height; border-radius: 0.25rem; } .searchbar-expanded { margin-left: 22vw; margin-right: auto; width: $searchbar-width !important; } .searchbar-collapsed { margin-left: auto; margin-right: $small-offset; width: $icon-width !important; transition: $transition-fast; } .searchbar { margin-left: auto; margin-right: auto; height: $icon-height !important; } .searchlabel { background-color: white !important; } .topbar { padding-top: $offset; margin-right: $offset; } .logout { font-size: x-large; } </style> <script> /* * This is Free Software under GNU Affero General Public License v >= 3.0 * without warranty, see README.md and license for details. * * SPDX-License-Identifier: AGPL-3.0-or-later * License-Filename: LICENSES/AGPL-3.0.txt * * Copyright (C) 2018 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH * * Author(s): * Thomas Junk <thomas.junk@intevation.de> */ import debounce from "lodash.debounce"; import { fromLonLat } from "ol/proj"; import { mapState } from "vuex"; import { displayError } from "../application/lib/errors.js"; import { HTTP } from "../application/lib/http"; import Identify from "../identify/Identify"; import Layers from "../layers/Layers"; const setFocus = () => document.querySelector("#search").focus(); export default { name: "topbar", components: { Identify: Identify, Layers: Layers }, data() { return { searchbarCollapsed: true, searchQuery: "", searchQueryIsDirty: false, searchResults: null, isSearching: false }; }, computed: { ...mapState("map", ["openLayersMap"]), ...mapState("fairwayprofile", ["currentProfile"]), searchIndicator: function() { if (this.isSearching) { return "⟳"; } else if (this.searchQueryIsDirty) { return ""; } else { return "✓"; } }, searchbarContainerStyle() { return { "input-group": true, searchcontainer: true, "searchbar-collapsed": this.searchbarCollapsed, "searchbar-expanded": !this.searchbarCollapsed }; } }, props: ["routeName"], watch: { searchQuery: function() { this.searchQueryIsDirty = true; this.triggerSearch(); } }, methods: { takeFirstSearchresult() { if (!this.searchResults || this.searchResults.length != 1) return; this.moveToSearchResult(this.searchResults[0]); }, triggerSearch: debounce(function() { this.doSearch(); }, 500), doSearch() { this.isCalculating = true; this.searchResults = null; if (this.searchQuery == "") { return; } HTTP.post( "/search", { string: this.searchQuery }, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-type": "text/xml; charset=UTF-8" } } ) .then(response => { // console.log("got:", response.data); this.searchResults = response.data; }) .catch(error => { const { status, data } = error.response; displayError({ title: "Backend Error", message: `${status}: ${data.message || data}` }); }); this.isCalculating = false; this.searchQueryIsDirty = false; }, moveToSearchResult(resultEntry) { // DEBUG console.log("Moving to", resultEntry); if (resultEntry.geom.type == "Point") { let view = this.openLayersMap.getView(); const currentZoom = view.getZoom(); let newZoom = 11; if (resultEntry.type === "bottleneck") newZoom = Math.max(17, currentZoom); if (resultEntry.type === "rhm") newZoom = Math.max(15, currentZoom); if (resultEntry.type === "city") newZoom = Math.max(13, currentZoom); view.animate( { zoom: newZoom, center: fromLonLat( resultEntry.geom.coordinates, view.getProjection() ) }, 700 ); } // this.searchQuery = ""; // clear search query again this.toggleSearchbar(); }, toggleSearchbar() { if (this.searchbarCollapsed) { setTimeout(setFocus, 300); } this.searchbarCollapsed = !this.searchbarCollapsed; }, toggleSidebar() { this.$store.commit("application/toggleSidebar"); }, splitScreen() { if (Object.keys(this.currentProfile).length == 0) return; this.$store.commit("application/toggleSplitScreen"); } } }; </script>