<template>
  <div :style="style" style="display: block" v-show="show" @mousedown.stop @mouseup.stop @contextmenu.prevent>
    <slot></slot>
  </div>
</template>

<script setup>
  const triggerShowFn = ref(() => {});
  const triggerHideFn = ref(() => {});
  const x = ref(null);
  const y = ref(null);
  const style = ref({});
  const binded = ref(false);

  const props = defineProps({
    target: null,
    show: Boolean
  });

  const $emit = defineEmits(['update:show']);

  watch(
    () => props.show,
    (show) => {
      if (show) {
        bindHideEvents();
      } else {
        unbindHideEvents();
      }
    }
  );

  watch(
    () => props.target,
    (target) => {
      bindEvents();
    }
  );

  // 初始化事件
  function bindEvents() {
    nextTick(() => {
      if (!props.target || binded.value) return;
      triggerShowFn.value = (event) => {
        contextMenuHandler(event);
      };
      props.target.addEventListener('contextmenu', triggerShowFn.value);
      props.target.addEventListener('mouseup', triggerShowFn.value);
      binded.value = true;
    });
  }

  // 取消绑定事件
  function unbindEvents() {
    if (!props.target) return;
    props.target.removeEventListener('contextmenu', triggerShowFn.value);
  }

  // 绑定隐藏菜单事件
  function bindHideEvents() {
    triggerHideFn.value = (event) => {
      clickDocumentHandler(event);
    };
    document.addEventListener('mousedown', triggerHideFn.value);
    document.addEventListener('mousewheel', triggerHideFn.value);
  }

  // 取消绑定隐藏菜单事件
  function unbindHideEvents() {
    document.removeEventListener('mousedown', triggerHideFn.value);
    document.removeEventListener('mousewheel', triggerHideFn.value);
  }

  // 鼠标按压事件处理器
  function clickDocumentHandler(e) {
    $emit('update:show', false);
  }

  // 右键事件事件处理
  function contextMenuHandler(e) {
    if (document.getSelection().toString()) {
      x.value = e.clientX;
      y.value = e.clientY;
      layout();
      $emit('update:show', true);
    }
    e.preventDefault();
  }

  // 布局
  function layout() {
    style.value = {
      left: x.value + 'px',
      top: y.value + 'px'
    };
  }
  onMounted(() => {
    bindEvents();
  });
</script>
