<template>
  <div
    ref="contextMenu"
    v-if="menuVisible"
    v-bind:style="menuStyle"
    v-on:blur="closeMenu"
    class="fm-context-menu"
    tabindex="-1"
  >
    <ul
      v-for="(group, index) in menu"
      v-bind:key="`g-${index}`"
      class="list-unstyled"
    >
      <li
        v-for="(item, index) in group"
        v-bind:key="`i-${index}`"
        v-on:click="menuAction(item.name)"
      >
        <template v-if="showMenuItem(item.name)">
          <i class="fa-fw" v-bind:class="item.icon" />
          {{ lang.contextMenu[item.name] }}
        </template>
      </li>
    </ul>
  </div>
</template>

<script>
/* eslint-disable no-param-reassign */
import EventBus from "@/utils/eventBus";
import translate from "@/utils/translate";
import contextMenu from "./mixins/contextMenu";
import contextMenuRules from "./mixins/contextMenuRules";
import contextMenuActions from "./mixins/contextMenuActions";

export default {
  name: "ContextMenu",
  mixins: [translate, contextMenu, contextMenuRules, contextMenuActions],
  data() {
    return {
      menuVisible: false,
      menuStyle: {
        top: 0,
        left: 0,
      },
    };
  },
  mounted() {
    /**
     * Listen events
     * 'contextMenu'
     */
    EventBus.$on("contextMenu", (event) => this.showMenu(event));
  },
  computed: {
    /**
     * Context menu items
     * @returns {*}
     */
    menu() {
      return this.$store.state.fm.settings.contextMenu;
    },
  },
  methods: {
    /**
     * Show context menu
     * @param event
     */
    showMenu(event) {
      if (this.selectedItems) {
        this.menuVisible = true;

        // focus on menu
        this.$nextTick(() => {
          this.$refs.contextMenu.focus();
          // set menu params
          this.setMenu(event.pageY, event.pageX);
        });
      }
    },

    /**
     * Set context menu coordinates
     * @param top
     * @param left
     */
    setMenu(top, left) {
      // get parent el (.fm-body)
      const el = this.$refs.contextMenu.parentNode;

      // get parent el size
      const elSize = el.getBoundingClientRect();

      // actual coordinates of the block
      const elY = window.pageYOffset + elSize.top;
      const elX = window.pageXOffset + elSize.left;

      // calculate the preliminary coordinates
      let menuY = top - elY;
      let menuX = left - elX;

      // calculate max X and Y coordinates
      const maxY =
        elY + (el.offsetHeight - this.$refs.contextMenu.offsetHeight - 25);
      const maxX =
        elX + (el.offsetWidth - this.$refs.contextMenu.offsetWidth - 25);

      if (top > maxY) menuY = maxY - elY;
      if (left > maxX) menuX = maxX - elX;

      // set coordinates
      this.menuStyle.top = `${menuY}px`;
      this.menuStyle.left = `${menuX}px`;
    },

    /**
     * Close context menu
     */
    closeMenu() {
      this.menuVisible = false;
    },

    /**
     * Show context menu item
     * @param name
     * @returns {*}
     */
    showMenuItem(name) {
      if (Object.prototype.hasOwnProperty.call(this, `${name}Rule`)) {
        return this[`${name}Rule`]();
      }

      return false;
    },

    /**
     * Call actions when clicking the context menu
     * @param name
     */
    menuAction(name) {
      if (Object.prototype.hasOwnProperty.call(this, `${name}Action`)) {
        this[`${name}Action`]();
      }
      // close context menu
      this.closeMenu();
    },
  },
};
</script>

<style lang="scss">
.fm-context-menu {
  position: absolute;
  z-index: 9997;
  background-color: white;
  box-shadow: 3px 2px 5px gray;
  border-radius: 5px;

  &:focus {
    outline: none;
  }

  .list-unstyled {
    margin-bottom: 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.125);
  }

  ul > li {
    padding: 0.4rem 1rem;
  }

  ul > li:not(.disabled) {
    cursor: pointer;

    &:hover {
      background-color: #f8f9fa;
    }

    i {
      padding-right: 2rem;
    }
  }
}
</style>