<template>
  <transition name="el-message-fade" @after-leave="handleAfterLeave">
    <div
        v-show="visible"
        :class="[
        'el-message','ed-message',

        center ? 'is-center' : '',
        showClose ? 'is-closable' : '',
        customClass
      ]"
        :style="positionStyle" role="alert"
        @mouseenter="clearTimer"
        @mouseleave="startTimer"
    >
      <div :class="['ed-message--content', type && !iconClass ? `el-message--${ type }` : '',]">
        <i v-if="iconClass" :class="iconClass"></i>
        <i v-else :class="typeClass"></i>
        <slot>
          <p v-if="!dangerouslyUseHTMLString" class="el-message__content">{{ message }}</p>
          <p v-else class="el-message__content" v-html="message"></p>
        </slot>
        <p v-if="showExtData" class="ed-message__extData" @click="handleExtra">
          <i>详情</i>
          <i class="el-icon-arrow-right"></i>
        </p>
        <i v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"></i>
      </div>

      <div v-show="showExtData && visibleExtData" :class="[
          'ed-message--extra',
          type && !iconClass ? `el-message--${ type }` : '',
          ]">
        <div class="el-message__cope" @click="handleCope">{{ copeText }}</div>
        <div class="el-message__content" v-html="getExtraMsg"></div>
      </div>
    </div>
  </transition>
</template>

<script type="text/babel">
const typeMap = {
  success: 'success',
  info: 'info',
  warning: 'warning',
  error: 'error'
};

export default {
  data() {
    return {
      visible: false,
      visibleExtData: false,
      showExtData: false,
      message: '',
      extraMsg: "",
      duration: 3000,
      type: 'info',
      iconClass: '',
      customClass: '',
      onClose: null,
      showClose: false,
      closed: false,
      verticalOffset: 20,
      timer: null,
      dangerouslyUseHTMLString: false,
      center: false,
      zIndex: 0,
      copeText: "复制",
      copeClick: null
    };
  },

  computed: {
    typeClass() {
      return this.type && !this.iconClass
          ? `el-message__icon el-icon-${typeMap[this.type]}`
          : '';
    },
    positionStyle() {
      return {
        'top': `${this.verticalOffset}px`,
        'z-index': this.zIndex
      };
    },
    getExtraMsg() {
      return this.extraMsg.replace(/\r\n/g, '<br/>')
    }
  },

  watch: {
    closed(newVal) {
      if (newVal) {
        this.visible = false;
      }
    },
    extraMsg: {
      immediate: true,
      handler(newVal) {
        if (newVal) {
          this.showExtData = true
        }
      }
    }
  },
  methods: {
    handleAfterLeave() {
      this.$destroy(true);
      this.$el.parentNode.removeChild(this.$el);
    },

    close() {
      this.closed = true;
      if (typeof this.onClose === 'function') {
        this.onClose(this);
      }
    },

    clearTimer() {
      clearTimeout(this.timer);
    },

    startTimer() {
      if (this.duration > 0) {
        this.timer = setTimeout(() => {
          if (!this.closed) {
            this.close();
          }
        }, this.duration);
      }
    },
    keydown(e) {
      if (e.keyCode === 27) { // esc关闭消息
        if (!this.closed) {
          this.close();
        }
      }
    },
    handleExtra() {
      this.visibleExtData = !this.visibleExtData
    },
    handleCope() {
      if (this.copeClick && typeof this.copeClick === 'function') {
        this.copeClick()
      } else {
        this.handleCopyValue(this.extraMsg).then(() => {
          console.log("已经复制到剪切板")
        }).catch(() => {
          console.log('复制失败')
        })
      }
    },
    /**
     * 复制到剪切板
     * @param text
     * @returns {Promise<never>|Promise<unknown>|Promise<void>}
     */
    handleCopyValue(text) {
      //浏览器禁用了非安全域的 navigator.clipboard 对象
      //在线上环境会报错 TypeError: Cannot read properties of undefined (reading 'writeText')
      if (!navigator.clipboard && window.isSecureContext) {
        return navigator.clipboard.writeText(text)
      } else {
        // 判断是否支持拷贝
        if (!document.execCommand('copy')) return Promise.reject()
        // 创建标签，并隐藏
        const textArea = document.createElement('textarea')
        textArea.style.position = 'fixed'
        textArea.style.top = textArea.style.left = '-100vh'
        textArea.style.opacity = '0'
        textArea.value = text
        document.body.appendChild(textArea)
        // 聚焦、复制
        textArea.focus()
        textArea.select()
        return new Promise((resolve, reject) => {
          // 不知为何，必须写这个三目，不然copy不上
          document.execCommand('copy') ? resolve() : reject()
          textArea.remove()
        })
      }
    }
  },
  mounted() {
    this.startTimer();
    document.addEventListener('keydown', this.keydown);
  },
  beforeDestroy() {
    document.removeEventListener('keydown', this.keydown);
  }
};
</script>
<style lang="scss" scoped>
.ed-message {
  overflow: initial !important;
  padding: 0;
}

.ed-message--content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
  width: 100%;
  padding: 15px 15px 15px 20px;

  .el-message__content {
    width: 100%;
  }

  .ed-message__extData {
    font-size: 12px;
    color: #409EFF;
    cursor: pointer;
    min-width: 50px;

    i {
      font-style: normal;
    }
  }

  .el-message__closeBtn {
    width: 20px;
    right: 0;
  }
}


.ed-message--extra {
  position: absolute;
  top: 58px;
  right: 0;
  left: 0;
  padding: 10px;
  border-radius: 4px;


  .el-message__content {
    line-height: 20px;
    word-wrap: break-word;
    max-height: 40vh;
    overflow-y: auto;
  }

  .el-message__cope {
    text-align: right;
    color: #409EFF;
    font-size: 12px;
    margin-bottom: 5px;
    cursor: pointer;
  }
}
</style>
