<template>
  <transition
    name="dialog-fade"
    @after-enter="afterEnter"
    @after-leave="afterLeave">
    <div
      v-show="visible"
      class="el-dialog__wrapper"
      :style="{'pointer-events': modalEvent ? 'auto' : 'none'}"
      @click.self="handleWrapperClick">
      <div
        role="dialog"
        :key="key"
        aria-modal="true"
        :aria-label="title || 'dialog'"
        :class="[
          'el-dialog',
          {
            'is-fullscreen': fullscreen,
            'el-dialog--center': center,
            'el-dialog--noPadding': !defaultPadding,
          },
          dialogSize ? 'el-dialog--' + dialogSize : '',
          className]"
        ref="dialog"
        :style="style">
        <div
          class="el-dialog__header relative"
          :class="{'el-dialog__header--hidden': !title, 'el-dialog-header-line': !title ? false : showHeaderLine}"
        >
          <span
            class="el-dialog__returnBtn mr-16 pointer"
            v-if="showReturn"
            @click="handleReturn"
          >
            <i class="el-icon-back mr-4"></i>
            <span class="text-14">返回</span>
          </span>
          <slot name="title">
            <span class="el-dialog__title">{{ title }}</span>
          </slot>
          <button
            type="button"
            class="el-dialog__headerbtn"
            aria-label="Close"                
            @click="handleClose">
            <i class="el-dialog__close el-icon el-icon-close"></i>
          </button>
        </div>
        <div
            class="el-dialog__body"
            :class="{'el-dialog__header--hidden__body': !title}"
            v-if="rendered"
            :style="{
                maxHeight: maxBodyHeight,
                overflow: 'auto'
            }"
        >
            <slot/>
        </div>
        <div class="el-dialog__footer" :class="{'el-dialog-footer-line': !title ? false : showFooterLine}" v-if="isShowFooter">
          <slot name="footer">
              <ElButton
                    @click="handleClose"
                    class='el-dialog__footerBtn'
                    v-if="cancelText"
                >
                    {{ cancelText }}
                </ElButton>
                <ElButton
                    :loading="loading"
                    type='primary'
                    class='el-dialog__footerBtn'
                    :class="{'el-dialog__footerBtn--center' :cancelText && center}"
                    @click="handleSubmit"
                >
                    {{ submitText }}
                </ElButton>
          </slot>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
  import Popup from 'element-ui/src/utils/popup';
  import Migrating from 'element-ui/src/mixins/migrating';
  import emitter from 'element-ui/src/mixins/emitter';
  import ElButton from 'element-ui/packages/button';
  import { delegate, on, off } from 'element-ui/src/utils/dom';
  export default {
    name: 'ElDialog',
    components: {
      ElButton
    },
    mixins: [Popup, emitter, Migrating],
    inject: {
      injectBeforeClose: {
        default: undefined
      }
    },
    props: {
      dragable: {
        type: Boolean,
        default: false
      },
      dragEl: {
        type: String,
        default: '.el-dialog__header'
      },
      loading: {
        type: Boolean,
        default: false
      },
      size: String,
      defaultPadding: {
        type: Boolean,
        default: true
      },
      submitText: {
        type: String,
        default: '确认'
      },
      cancelText: {
        type: String,
        default: '取消'
      },
      title: {
        type: String,
        default: ''
      },

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

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

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

      closeOnClickModal: {
        type: Boolean,
        default: false
      },
      maxBodyHeight: {
        type: String,
        default: '56vh'
      },
      closeOnPressEscape: {
        type: Boolean,
        default: true
      },
      showClose: {
        type: Boolean,
        default: true
      },
      isShowFooter: {
        type: Boolean,
        default: true
      },
      width: String,

      fullscreen: Boolean,

      className: {
        type: String,
        default: ''
      },
      beforeClose: {
        default() {
          return this.injectBeforeClose;
        }
      },
      submitHandle: Function,
      center: {
        type: Boolean,
        default: false
      },

      destroyOnClose: Boolean,
      showReturn: {
        type: Boolean,
        default: false
      },
      returnHandle: Function,
      basePosition: {
        type: Object,
        default: ()=> {}
      },
      showHeaderLine: {
        type: Boolean,
        default: true
      },
      showFooterLine: {
        type: Boolean,
        default: true
      }
    },

    data() {
      return {
        closed: false,
        key: 0,
        dragFixConfig: {
          fixLeft: 0,
          fixTop: 0,
          maxHeight: 0,
          maxWidth: 0
        }
      };
    },

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

    computed: {
      dialogSize() {
        return this.size || (this.$ELEMENT || {}).size;
      },
      style() {
        let style = {
          pointerEvents: 'auto'
        };
        if (!this.fullscreen) {
          if (this.width) {
            style.width = this.width;
          }
        }
        return style;
      }
    },

    methods: {
      setBaseStyle() {
        this.unsetDialogPostion();
        for (const key in this.basePosition) {
          if (Object.hasOwnProperty.call(this.basePosition, key)) {
            const element = this.basePosition[key];
            this.$refs.dialog.style[key] = element;
          }
        }
      },
      unsetDialogPostion() {
        this.$refs.dialog.style.position = null;
        this.$refs.dialog.style.top = null;
        this.$refs.dialog.style.left = null;
        this.$refs.dialog.style.right = null;
        this.$refs.dialog.style.bottom = null;
      },
      handleWrapperClick() {
        if (!this.closeOnClickModal) return;
        this.handleClose();
      },
      handleClose() {
        if (typeof this.beforeClose === 'function') {
          this.beforeClose(this.hide);
        } else {
          this.hide();
        }
      },
      handleSubmit() {
        if (typeof this.submitHandle === 'function') {
          this.submitHandle(this.hide);
        } else {
          this.hide();
        }
      },
      hide(cancel) {
        if (cancel !== false) {
          this.$emit('update:visible', false);
          this.$emit('close');
          this.closed = true;
        }
      },
      updatePopper() {
        this.broadcast('ElSelectDropdown', 'updatePopper');
        this.broadcast('ElDropdownMenu', 'updatePopper');
      },
      afterEnter() {
        this.$emit('opened');
      },
      afterLeave() {
        this.$emit('closed');
      },
      handleReturn() {
        if (typeof this.returnHandle === 'function') {
          this.returnHandle(this.hide);
        } else {
          this.hide();
        }
      },
      setPositonByMouse(event) {
        const realTop = event.pageY - this.dragFixConfig.fixTop;
        const realLeft = event.pageX - this.dragFixConfig.fixLeft;
        const top = realTop < this.dragFixConfig.maxHeight ? Math.max(realTop, 0) : this.dragFixConfig.maxHeight;
        const left = realLeft < this.dragFixConfig.maxWidth ? Math.max(realLeft, 0) : this.dragFixConfig.maxWidth;
        this.$refs.dialog.style.top = top + 'px';
        this.$refs.dialog.style.left = left + 'px';
      },
      dragIngHandle(event) {
        this.setPositonByMouse(event);
        if (event.which !== 1) {
          this.dragEndHandle(event);
        }
      },
      dragEndHandle() {
        off(document, 'mousemove', this.dragIngHandle);
        off(document, 'mouseUp', this.dragIngHandle);
      },
      cleanDragHandle() {
        off(document, 'mousemove', this.dragIngHandle);
        off(document, 'mouseUp', this.dragIngHandle);
        // on(this.$refs.dialog, 'mousedown', this.dragStartHandle);
        off(this.$refs.dialog, 'mousedown');
        // const dragEl = this.$el.querySelectorAll(this.dragEl);
        // dragEl.forEach(e => {
        //   e.removeEventListener('mousedown', this.dragStartHandle);
        // });
      },
      dragStartHandle(event) {
        event.preventDefault();
        const el = this.$refs.dialog;
        const rectObj = el.getBoundingClientRect();
        this.dragFixConfig.maxHeight = window.innerHeight - rectObj.height;
        this.dragFixConfig.maxWidth = window.innerWidth - rectObj.width;
        this.dragFixConfig.fixLeft = event.clientX - rectObj.left;
        this.dragFixConfig.fixTop = event.clientY - rectObj.top;
        this.unsetDialogPostion();
        el.style.position = 'absolute';
        this.setPositonByMouse(event);
        on(document, 'mousemove', this.dragIngHandle);
        on(document, 'mouseUp', this.dragIngHandle);
      },
      bindDrag() {
        delegate(this.$el, this.dragEl, 'mousedown', this.dragStartHandle);
      }
    },

    mounted() {
      if (this.visible) {
        this.rendered = true;
        this.setBaseStyle();
        this.open();
        if (this.dragable) {
          this.bindDrag();
        }
        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);
      }
      this.cleanDragHandle();
    }
  };
</script>
