浏览代码

HUE-9485 [frontend] Add a click outside directive and enable it in the Vue Dropdown component

Johan Ahlen 5 年之前
父节点
当前提交
a76f074fdb

+ 43 - 0
desktop/core/src/desktop/js/components/directives/clickOutsideDirective.ts

@@ -0,0 +1,43 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// 'License'); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { DirectiveOptions } from 'vue';
+
+interface ClickOutsideHTMLElement extends HTMLElement {
+  clickOutsideHandler?: (event: MouseEvent) => void;
+}
+
+export const clickOutsideDirective: DirectiveOptions = {
+  bind: (element: ClickOutsideHTMLElement, binding, vNode) => {
+    element.clickOutsideHandler = (event: MouseEvent) => {
+      if (
+        vNode.context &&
+        vNode.context[binding.expression] &&
+        document.contains(<Node>event.target) &&
+        !element.contains(<Node>event.target)
+      ) {
+        vNode.context[binding.expression](event);
+      }
+    };
+    document.addEventListener('click', element.clickOutsideHandler);
+  },
+  unbind: (element: ClickOutsideHTMLElement) => {
+    if (element.clickOutsideHandler) {
+      document.removeEventListener('click', element.clickOutsideHandler);
+      element.clickOutsideHandler = undefined;
+    }
+  }
+};

+ 13 - 2
desktop/core/src/desktop/js/components/dropdown/Dropdown.vue

@@ -17,7 +17,7 @@
 -->
 -->
 
 
 <template>
 <template>
-  <div :class="{ 'dropdown-inline': inline }">
+  <div v-click-outside="clickOutside" :class="{ 'dropdown-inline': inline }">
     <hue-link v-if="inline" @click="toggleMenu">
     <hue-link v-if="inline" @click="toggleMenu">
       {{ text }} <i class="fa fa-caret-down" />
       {{ text }} <i class="fa fa-caret-down" />
     </hue-link>
     </hue-link>
@@ -33,13 +33,18 @@
 </template>
 </template>
 
 
 <script lang="ts">
 <script lang="ts">
+  import { clickOutsideDirective } from '../directives/clickOutsideDirective';
   import HueButton from '../HueButton.vue';
   import HueButton from '../HueButton.vue';
   import HueLink from '../HueLink.vue';
   import HueLink from '../HueLink.vue';
   import Vue from 'vue';
   import Vue from 'vue';
   import Component from 'vue-class-component';
   import Component from 'vue-class-component';
   import { Prop } from 'vue-property-decorator';
   import { Prop } from 'vue-property-decorator';
+
   @Component({
   @Component({
-    components: { HueButton, HueLink }
+    components: { HueButton, HueLink },
+    directives: {
+      'click-outside': clickOutsideDirective
+    }
   })
   })
   export default class Dropdown extends Vue {
   export default class Dropdown extends Vue {
     @Prop({ required: false, default: '' })
     @Prop({ required: false, default: '' })
@@ -52,6 +57,12 @@
     toggleMenu(): void {
     toggleMenu(): void {
       this.menuOpen = !this.menuOpen;
       this.menuOpen = !this.menuOpen;
     }
     }
+
+    clickOutside(): void {
+      if (this.menuOpen) {
+        this.menuOpen = false;
+      }
+    }
   }
   }
 </script>
 </script>