changeset 1196:a397b52981b8

html cleanup got rid of Topbar.vue to avoid unnecessary component nesting
author Markus Kottlaender <markus@intevation.de>
date Mon, 19 Nov 2018 08:24:47 +0100
parents 486d66a9565c
children 49740dcba52c
files client/src/App.vue client/src/application/Search.vue client/src/application/Topbar.vue
diffstat 3 files changed, 217 insertions(+), 245 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/App.vue	Sun Nov 18 18:44:22 2018 +0100
+++ b/client/src/App.vue	Mon Nov 19 08:24:47 2018 +0100
@@ -2,7 +2,14 @@
     <div id="app" class="main">
         <div v-if="isAuthenticated" class="d-flex flex-column userinterface">
             <div class="topcontainer">
-                <Topbar :routeName="routeName"></Topbar>
+                <div class="topbar d-flex flex-row">
+                    <Sidebar :routeName="routeName"></Sidebar>
+                    <Bottlenecks v-if="routeName == 'mainview'"></Bottlenecks>
+                    <Imports v-if="routeName == 'mainview'"></Imports>
+                    <Search v-if="routeName == 'mainview'"></Search>
+                    <Layers v-if="routeName == 'mainview'"></Layers>
+                    <Identify v-if="routeName == 'mainview'"></Identify>
+                </div>
             </div>
             <div class="flex-fill"></div>
             <div class="bottomcontainer d-flex flex-row align-items-end">
@@ -34,6 +41,11 @@
   z-index: 4
   pointer-events: none
 
+.topbar
+  padding-top: $offset
+  margin-left: $offset
+  margin-right: $offset
+
 #app
   height: 100vh
   width: 100vw
@@ -72,11 +84,16 @@
     }
   },
   components: {
-    Topbar: () => import("./application/Topbar"),
     Drawtool: () => import("./drawtool/Drawtool"),
     Morphtool: () => import("./morphtool/Morphtool"),
     Pdftool: () => import("./pdftool/Pdftool"),
-    Zoom: () => import("./zoom/zoom")
+    Zoom: () => import("./zoom/zoom"),
+    Identify: () => import("./identify/Identify"),
+    Layers: () => import("./layers/Layers"),
+    Sidebar: () => import("./application/Sidebar"),
+    Search: () => import("./application/Search"),
+    Bottlenecks: () => import("./bottlenecks/Bottlenecks"),
+    Imports: () => import("./imports/Imports.vue")
   }
 };
 </script>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/application/Search.vue	Mon Nov 19 08:24:47 2018 +0100
@@ -0,0 +1,197 @@
+<template>
+    <div :class="searchbarContainerStyle">
+        <div class="input-group-prepend shadow">
+            <span @click="toggleSearchbar" :class="searchButtonStyle" for="search">
+                <i class="fa fa-search d-print-none"></i>
+            </span>
+        </div>
+        <div class="searchgroup flex-fill">
+            <input
+                @keyup.enter="takeFirstSearchresult"
+                v-if="showSearchbar"
+                id="search"
+                v-model="searchQuery"
+                type="text"
+                class="form-control ui-element search searchbar d-print-none"
+            >
+            <ul v-if="showSearchbar && 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>
+</template>
+
+<style lang="sass" scoped>
+  .searchcontainer
+    height: $icon-height
+    border-radius: 0.25rem
+
+  .searchbar-expanded
+    margin-left: auto
+    margin-right: auto
+    padding-left: $offset
+    width: $searchbar-width !important
+    .searchbar
+      border-top-left-radius: 0 !important
+      border-bottom-left-radius: 0 !important
+
+
+  .searchbar-collapsed
+    margin-left: auto
+    width: $icon-width !important
+    transition: $transition-fast
+
+  .searchbar
+    margin-left: auto
+    margin-right: auto
+    height: $icon-height !important
+
+  .searchlabel
+    background-color: white !important
+
+  .input-group-text
+    height: $icon-height
+    width: $icon-width
+
+  .list-group
+    pointer-events: auto
+</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 } from "vuex";
+
+import { displayError } from "../application/lib/errors.js";
+import { HTTP } from "../application/lib/http";
+
+const setFocus = () => document.querySelector("#search").focus();
+
+export default {
+  name: "search",
+  data() {
+    return {
+      searchQuery: "",
+      searchQueryIsDirty: false,
+      searchResults: null,
+      isSearching: false
+    };
+  },
+  computed: {
+    ...mapState("application", ["showSearchbar"]),
+    searchIndicator: function() {
+      if (this.isSearching) {
+        return "⟳";
+      } else if (this.searchQueryIsDirty) {
+        return "";
+      } else {
+        return "✓";
+      }
+    },
+    searchbarContainerStyle() {
+      return [
+        "d-flex input-group searchcontainer",
+        {
+          "searchbar-collapsed": !this.showSearchbar,
+          "searchbar-expanded": this.showSearchbar
+        }
+      ];
+    },
+    searchButtonStyle() {
+      return [
+        "ui-element input-group-text p-0 d-flex justify-content-center searchlabel d-print-none",
+        {
+          rounded: !this.showSearchbar,
+          "rounded-left": this.showSearchbar
+        }
+      ];
+    }
+  },
+  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 zoom = 11;
+        if (resultEntry.type === "bottleneck") zoom = 17;
+        if (resultEntry.type === "rhm") zoom = 15;
+        if (resultEntry.type === "city") zoom = 13;
+
+        this.$store.commit("map/moveMap", {
+          coordinates: resultEntry.geom.coordinates,
+          zoom,
+          preventZoomOut: true
+        });
+      }
+      // this.searchQuery = ""; // clear search query again
+      this.toggleSearchbar();
+    },
+    toggleSearchbar() {
+      if (!this.showSearchbar) {
+        setTimeout(setFocus, 300);
+      }
+      this.$store.commit("application/showSearchbar", !this.showSearchbar);
+    }
+  }
+};
+</script>
--- a/client/src/application/Topbar.vue	Sun Nov 18 18:44:22 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-<template>
-    <div class="topbar d-flex flex-row">
-        <Sidebar :routeName="routeName"></Sidebar>
-        <Bottlenecks v-if="routeName == 'mainview'"></Bottlenecks>
-        <Imports v-if="routeName == 'mainview'"></Imports>
-        <div v-if="routeName == 'mainview'" :class="searchbarContainerStyle">
-            <div class="input-group-prepend shadow">
-                <span @click="toggleSearchbar" :class="searchButtonStyle" for="search">
-                    <i class="fa fa-search d-print-none"></i>
-                </span>
-            </div>
-            <div class="searchgroup flex-fill">
-                <input
-                    @keyup.enter="takeFirstSearchresult"
-                    v-if="showSearchbar"
-                    id="search"
-                    v-model="searchQuery"
-                    type="text"
-                    class="form-control ui-element search searchbar d-print-none"
-                >
-                <ul v-if="showSearchbar && 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 class="">
-            <Layers v-if="routeName == 'mainview'"></Layers>
-        </div>
-        <div class="">
-            <Identify v-if="routeName == 'mainview'"></Identify>
-        </div>
-    </div>
-</template>
-
-<style lang="sass" scoped>
-.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
-
-.searchcontainer
-  height: $icon-height
-  border-radius: 0.25rem
-
-.searchbar-expanded
-  margin-left: auto
-  margin-right: auto
-  padding-left: $offset
-  width: $searchbar-width !important
-  .searchbar
-    border-top-left-radius: 0 !important
-    border-bottom-left-radius: 0 !important
-
-
-.searchbar-collapsed
-  margin-left: auto
-  width: $icon-width !important
-  transition: $transition-fast
-
-.searchbar
-  margin-left: auto
-  margin-right: auto
-  height: $icon-height !important
-
-.searchlabel
-  background-color: white !important
-
-.input-group-text
-  height: $icon-height
-  width: $icon-width
-
-.topbar
-  padding-top: $offset
-  margin-left: $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 { mapState } from "vuex";
-
-import { displayError } from "../application/lib/errors.js";
-import { HTTP } from "../application/lib/http";
-
-const setFocus = () => document.querySelector("#search").focus();
-
-export default {
-  name: "topbar",
-  components: {
-    Identify: () => import("../identify/Identify"),
-    Layers: () => import("../layers/Layers"),
-    Sidebar: () => import("./Sidebar"),
-    Bottlenecks: () => import("../bottlenecks/Bottlenecks"),
-    Imports: () => import("../imports/Imports.vue")
-  },
-  data() {
-    return {
-      searchQuery: "",
-      searchQueryIsDirty: false,
-      searchResults: null,
-      isSearching: false
-    };
-  },
-  computed: {
-    ...mapState("application", [
-      "showSidebar",
-      "showSplitscreen",
-      "showSearchbar"
-    ]),
-    ...mapState("map", ["openLayersMap"]),
-    ...mapState("fairwayprofile", ["currentProfile"]),
-    searchIndicator: function() {
-      if (this.isSearching) {
-        return "⟳";
-      } else if (this.searchQueryIsDirty) {
-        return "";
-      } else {
-        return "✓";
-      }
-    },
-    searchbarContainerStyle() {
-      return [
-        "d-flex input-group searchcontainer",
-        {
-          "searchbar-collapsed": !this.showSearchbar,
-          "searchbar-expanded": this.showSearchbar
-        }
-      ];
-    },
-    searchButtonStyle() {
-      return [
-        "ui-element input-group-text p-0 d-flex justify-content-center searchlabel d-print-none",
-        {
-          rounded: !this.showSearchbar,
-          "rounded-left": this.showSearchbar
-        }
-      ];
-    }
-  },
-  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 zoom = 11;
-        if (resultEntry.type === "bottleneck") zoom = 17;
-        if (resultEntry.type === "rhm") zoom = 15;
-        if (resultEntry.type === "city") zoom = 13;
-
-        this.$store.commit("map/moveMap", {
-          coordinates: resultEntry.geom.coordinates,
-          zoom,
-          preventZoomOut: true
-        });
-      }
-      // this.searchQuery = ""; // clear search query again
-      this.toggleSearchbar();
-    },
-    toggleSearchbar() {
-      if (!this.showSearchbar) {
-        setTimeout(setFocus, 300);
-      }
-      this.$store.commit("application/showSearchbar", !this.showSearchbar);
-    }
-  }
-};
-</script>