Mercurial > gemma
view client/src/components/Search.vue @ 4231:6f31a99cd92d
clinet: fix translations process and update source strings
* move strings for translations from *.po files to the component itself to let gettext() mark only the strings without the html elements.
(make makemessages complains to have html elements in the .po files and stops the process).
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Wed, 21 Aug 2019 11:13:12 +0200 |
parents | 33180c25bd87 |
children | 1cdd246860ae |
line wrap: on
line source
<template> <div :class="searchbarContainerStyle"> <div class="input-group-prepend m-0 d-print-none"> <span @click="toggleSearchbar" :class="searchButtonStyle" for="search"> <font-awesome-icon icon="search" /> </span> </div> <div :class="[ 'searchgroup', { 'searchgroup-collapsed': !showSearchbar, big: showContextBox && ['bottlenecks', 'staging', 'stretches'].indexOf( contextBoxContent ) !== -1 } ]" > <input @keyup.enter="triggerEnter" id="search" v-model="searchQuery" type="text" :class="searchInputStyle" /> </div> <div v-if="showSearchbar && searchResults !== null && !showContextBox" class="searchresults border-top ui-element bg-white rounded-bottom d-print-none position-absolute" > <div v-for="(entry, index) of searchResults" :key="index" class="border-top text-left" > <a href="#" @click.prevent="moveToSearchResult(entry)" class="p-2 d-block text-nowrap" > <font-awesome-icon icon="ship" v-if="entry.type === 'bottleneck'" class="mr-1" fixed-width /> <font-awesome-icon icon="water" v-if="entry.type === 'rhm'" class="mr-1" fixed-width /> <font-awesome-icon icon="city" v-if="entry.type === 'city'" class="mr-1" fixed-width /> <font-awesome-icon icon="ruler-vertical" v-if="entry.type === 'gauge'" class="mr-1" fixed-width /> <font-awesome-icon icon="road" v-if="['stretch', 'section'].includes(entry.type)" class="mr-1" fixed-width /> {{ entry.name }} <span v-if="entry.location || entry.locationcode" >({{ entry.location }}<span v-if="entry.location && entry.locationcode">, </span >{{ entry.locationcode }})</span > </a> </div> </div> </div> </template> <style lang="scss" scoped> .searchcontainer { opacity: 0.96; width: 668px; } .searchcontainer .searchbar { border-top-left-radius: 0 !important; border-bottom-left-radius: 0 !important; } .searchgroup { width: 635px; overflow: hidden; } .searchgroup-collapsed { width: 0; } .searchbar { height: 2rem !important; box-shadow: none !important; } .searchbar.rounded-top-right { border-radius: 0 !important; border-top-right-radius: 0.25rem !important; } .searchlabel.rounded-top-left { border-radius: 0 !important; border-top-left-radius: 0.25rem !important; } .input-group-text { height: 2rem; width: 2rem; } .input-group-prepend svg path { fill: #666; } .searchresults { box-shadow: 0 0.1rem 0.5rem rgba(0, 0, 0, 0.2); top: 2rem; left: 0; right: 0; max-height: 24rem; overflow: auto; } .searchresults > div:first-child { border-top: 0 !important; } .searchresults a { text-decoration: none; } .searchresults a:hover { background: #f8f8f8; } .smallbox { width: 2rem; } </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): * Markus Kottländer <markus.kottlaender@intevation.de> */ import debounce from "lodash.debounce"; import { mapState, mapGetters } from "vuex"; import { displayError } from "@/lib/errors"; import { HTTP } from "@/lib/http"; import { format } from "date-fns"; const setFocus = () => document.querySelector("#search").focus(); export default { name: "search", data() { return { searchQueryIsDirty: false, searchResults: null, isSearching: false }; }, computed: { ...mapState("application", [ "showSearchbar", "showContextBox", "contextBoxContent" ]), ...mapState("imports", ["startDate", "endDate"]), ...mapGetters("imports", ["filters"]), ...mapGetters("map", ["openLayersMap"]), searchQuery: { get() { return this.$store.state.application.searchQuery; }, set(value) { this.$store.commit("application/searchQuery", value); } }, searchIndicator: function() { if (this.isSearching) { return "⟳"; } else if (this.searchQueryIsDirty) { return ""; } else { return "✓"; } }, searchbarContainerStyle() { return [ "input-group searchcontainer shadow-xs rounded", { "d-flex": this.contextBoxContent !== "imports", "d-none": this.contextBoxContent === "imports" && this.showContextBox, smallbox: !this.showSearchbar } ]; }, searchInputStyle() { return [ "form-control ui-element search searchbar d-print-none border-0", { "rounded-top-right": this.showContextBox || this.searchResults } ]; }, searchButtonStyle() { return [ "ui-element input-group-text p-0 d-flex border-0 justify-content-center searchlabel bg-white d-print-none", { rounded: !this.showSearchbar, "rounded-left": this.showSearchbar, "rounded-top-left": this.showSearchbar && (this.showContextBox || this.searchResults) } ]; } }, watch: { searchQuery: function() { this.searchQueryIsDirty = true; if (!this.showContextBox) this.triggerSearch(); } }, methods: { loadLogs() { this.$store .dispatch("imports/getImports", { filter: this.filters, from: format(this.startDate, "YYYY-MM-DDTHH:mm:ss.SSS"), to: format(this.endDate, "YYYY-MM-DDTHH:mm:ss.SSS"), query: this.searchQuery }) .then(() => {}) .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }, triggerEnter() { if (this.showContextBox && this.contextBoxContent === "importoverview") { this.loadLogs(); } 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 => { this.searchResults = response.data; }) .catch(error => { const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); this.isCalculating = false; this.searchQueryIsDirty = false; }, moveToSearchResult(resultEntry) { let zoom = 16; if (resultEntry.type === "bottleneck") { this.openLayersMap() .getLayer("BOTTLENECKS") .setVisible(true); } if (resultEntry.type === "rhm") { this.openLayersMap() .getLayer("DISTANCEMARKSAXIS") .setVisible(true); } if (resultEntry.type === "gauge") { this.openLayersMap() .getLayer("GAUGES") .setVisible(true); } if (resultEntry.type === "stretch") { this.$store.commit( "imports/selectedStretchId", "stretches_geoserver." + resultEntry.id ); this.openLayersMap() .getLayer("STRETCHES") .setVisible(true); } if (resultEntry.type === "section") { this.$store.commit( "imports/selectedSectionId", "sections_geoserver." + resultEntry.id ); this.openLayersMap() .getLayer("SECTIONS") .setVisible(true); } if (resultEntry.type === "city") zoom = 13; if (resultEntry.geom.type == "Point") { this.$store.dispatch("map/moveMap", { coordinates: resultEntry.geom.coordinates, zoom, preventZoomOut: true }); } else if (resultEntry.geom.type == "Polygon") { const boundingBox = [ Math.min(...resultEntry.geom.coordinates[0].map(c => c[0])), Math.min(...resultEntry.geom.coordinates[0].map(c => c[1])), Math.max(...resultEntry.geom.coordinates[0].map(c => c[0])), Math.max(...resultEntry.geom.coordinates[0].map(c => c[1])) ]; this.$store.dispatch("map/moveToBoundingBox", { boundingBox, zoom }); } // this.searchQuery = ""; // clear search query again this.toggleSearchbar(); }, toggleSearchbar() { if (!this.showContextBox) { if (!this.showSearchbar) { setTimeout(setFocus, 300); } this.$store.commit("application/showSearchbar", !this.showSearchbar); } } } }; </script>