TheContextMenu.vue 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. <script setup lang="ts">
  2. import { coerceNodeId } from '@/ua/NodeId';
  3. import { UABaseNode } from '@/ua/UABaseNode';
  4. import { assert } from '@/util/assert';
  5. import { useStore } from '@/store';
  6. import { ref, reactive, onMounted, onUnmounted, computed, type CSSProperties } from 'vue';
  7. const isVisible = ref(false);
  8. const menuPosition = reactive({ top: "0px", left: "0px" });
  9. const store = useStore();
  10. const openMenu = (event: any) => {
  11. isVisible.value = true;
  12. menuPosition.top = event.layerY + 'px';
  13. menuPosition.left = event.layerX + 'px';
  14. };
  15. const closeMenu = () => {
  16. isVisible.value = false;
  17. };
  18. const newInstance = () => {
  19. assert(store.addressSpace!=null)
  20. store.selectedNode = new UABaseNode({browseName: "new node", addressSpace: store.addressSpace, nodeId: coerceNodeId("ns=0;i=999999")});
  21. closeMenu();
  22. };
  23. const menuStyle = computed<CSSProperties>(() => ({
  24. position: "absolute",
  25. top: menuPosition.top,
  26. left: menuPosition.left,
  27. zIndex: 5,
  28. }));
  29. const handleClickOutside = (event: any) => {
  30. if (!event.target.closest('.context-menu')) {
  31. closeMenu();
  32. }
  33. };
  34. onMounted(() => {
  35. document.addEventListener('click', handleClickOutside);
  36. });
  37. onUnmounted(() => {
  38. document.removeEventListener('click', handleClickOutside);
  39. });
  40. </script>
  41. <style scoped>
  42. .context-menu {
  43. border: 1px solid #ccc;
  44. background-color: white;
  45. padding: 10px;
  46. box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
  47. }
  48. </style>
  49. <template>
  50. <div @contextmenu.prevent="openMenu($event)">
  51. <slot></slot>
  52. <div v-if="isVisible" :style="menuStyle" class="context-menu">
  53. <button @click="newInstance">new instance</button>
  54. </div>
  55. </div>
  56. </template>