<template>
  <transition name="modal-fade"
              @after-enter="afterEnter"
              @after-leave="afterLeave">
    <div v-show="visible"
         v-modalDrag="draggable"
         class="xb-modal__wrapper"
         :class="{'is-draggable':draggable}"
         @click.self="handleWrapperClick">
      <div role="modal"
           :key="key"
           aria-modal="true"
           :aria-label="title || 'modal'"
           :class="['xb-modal', { 'is-fullscreen': fullscreen, 'xb-modal--center': center }, customClass]"
           ref="modal"
           :style="style">
        <button type="button"
                class="xb-modal__headerbtn"
                aria-label="Close"
                v-if="showClose"
                @click="handleClose">
          <i class="xb-modal__close xb-icon xb_icon_close_linear"></i>
        </button>
        <div class="xb-modal__header">
          <slot name="title">
            <span class="xb-modal__title">{{ title }}</span>
          </slot>
        </div>
        <div class="xb-modal__body"
             v-if="rendered">
          <slot></slot>
        </div>
        <div class="xb-modal__footer"
             v-if="$slots.footer">
          <slot name="footer"></slot>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
import Popup from 'xinbao-ui/src/utils/popup';
import Migrating from 'xinbao-ui/src/mixins/migrating';
import emitter from 'xinbao-ui/src/mixins/emitter';

export default {
  name: 'XbModal',

  mixins: [Popup, emitter, Migrating],

  props: {
    title: {
      type: String,
      default: ''
    },

    modal: {
      type: Boolean,
      default: true
    },

    modalAppendToBody: {
      type: Boolean,
      default: true
    },

    appendToBody: {
      type: Boolean,
      default: false
    },

    lockScroll: {
      type: Boolean,
      default: true
    },

    closeOnClickModal: {
      type: Boolean,
      default: false
    },

    closeOnPressEscape: {
      type: Boolean,
      default: true
    },

    showClose: {
      type: Boolean,
      default: true
    },

    width: String,

    fullscreen: Boolean,

    customClass: {
      type: String,
      default: ''
    },

    top: {
      type: String,
      default: '15vh'
    },
    beforeClose: Function,
    center: {
      type: Boolean,
      default: false
    },

    destroyOnClose: Boolean,

    draggable: {
      type: Boolean,
      default: false
    }
  },

  directives: {
    modalDrag: {
      bind(el, binding, vnode, oldVnode) {
        if (binding.value) {
          const modalHeaderEl = el.querySelector('.xb-modal__header');
          const dragDom = el.querySelector('.xb-modal');
          modalHeaderEl.style.cssText += ';cursor:move;';
          dragDom.style.cssText += ';top:0px;';

          // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
          const sty = (function() {
            if (window.document.currentStyle) {
              return (dom, attr) => dom.currentStyle[attr];
            } else {
              return (dom, attr) => getComputedStyle(dom, false)[attr];
            }
          })();

          modalHeaderEl.onmousedown = (e) => {
            // 鼠标按下，计算当前元素距离可视区的距离
            const disX = e.clientX - modalHeaderEl.offsetLeft;
            const disY = e.clientY - modalHeaderEl.offsetTop;

            const screenWidth = document.body.clientWidth; // body当前宽度
            const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度，可某些环境下无法获取)

            const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
            const dragDomheight = dragDom.offsetHeight; // 对话框高度

            const minDragDomLeft = dragDom.offsetLeft;
            const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;

            const minDragDomTop = dragDom.offsetTop;
            const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;

            // 获取到的值带px 正则匹配替换
            let styL = sty(dragDom, 'left');
            let styT = sty(dragDom, 'top');

            // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
            if (styL.includes('%')) {
              styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
              styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
            } else {
              styL = +styL.replace(/\px/g, '');
              styT = +styT.replace(/\px/g, '');
            };

            document.onmousemove = function(e) {
              // 通过事件委托，计算移动的距离
              let left = e.clientX - disX;
              let top = e.clientY - disY;

              // 边界处理
              if (-(left) > minDragDomLeft) {
                left = -(minDragDomLeft);
              } else if (left > maxDragDomLeft) {
                left = maxDragDomLeft;
              }

              if (-(top) > minDragDomTop) {
                top = -(minDragDomTop);
              } else if (top > maxDragDomTop) {
                top = maxDragDomTop;
              }

              // 移动当前元素
              dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
            };

            document.onmouseup = function(e) {
              document.onmousemove = null;
              document.onmouseup = null;
            };
          };
        }
      }
    }
  },

  data() {
    return {
      closed: false,
      key: 0
    };
  },

  watch: {
    visible(val) {
      if (val) {
        this.closed = false;
        this.$emit('open');
        this.$el.addEventListener('scroll', this.updatePopper);
        this.$nextTick(() => {
          this.$refs.modal.scrollTop = 0;
        });
        if (this.appendToBody) {
          document.body.appendChild(this.$el);
        }
      } else {
        this.$el.removeEventListener('scroll', this.updatePopper);
        if (!this.closed) this.$emit('close');
        if (this.destroyOnClose) {
          this.$nextTick(() => {
            this.key++;
          });
        }
      }
    }
  },

  computed: {
    style() {
      let style = {};
      if (!this.fullscreen) {
        style.marginTop = this.top;
        if (this.width) {
          style.width = this.width;
        }
      }
      return style;
    }
  },

  methods: {
    getMigratingConfig() {
      return {
        props: {
          'size': 'size is removed.'
        }
      };
    },
    handleWrapperClick() {
      if (!this.closeOnClickModal) return;
      this.handleClose();
    },
    handleClose() {
      if (typeof this.beforeClose === 'function') {
        this.beforeClose(this.hide);
      } else {
        this.hide();
      }
    },
    hide(cancel) {
      if (cancel !== false) {
        this.$emit('update:visible', false);
        this.$emit('close');
        this.closed = true;
      }
    },
    updatePopper() {
      this.broadcast('XbSelectDropdown', 'updatePopper');
      this.broadcast('XbDropdownMenu', 'updatePopper');
    },
    afterEnter() {
      this.$emit('opened');
    },
    afterLeave() {
      this.$emit('closed');
    }
  },

  mounted() {
    if (this.visible) {
      this.rendered = true;
      this.open();
      if (this.appendToBody) {
        document.body.appendChild(this.$el);
      }
    }
  },

  destroyed() {
    // if appendToBody is true, remove DOM node after destroy
    if (this.appendToBody && this.$el && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el);
    }
  }
};
</script>
