<template>
  <div class="xx-ellipsis">
    <slot name="prefix" class="xx-ellipsis-prefix"></slot>
    <div class="xx-ellipsis-hidden">
      <span class="xx-ellipsis-text" ref="text">{{ text }}</span>
      <span class="xx-ellipsis-more" ref="more" v-show="oversize"
        ><slot name="more">...</slot></span
      >
      <slot name="suffix" class="xx-ellipsis-suffix"></slot>
    </div>
  </div>
</template>

<script>
import XxTooltip from 'xxqx-ui/packages/tooltip'
export default {
  name: 'XxEllipsis',
  components: { XxTooltip },
  props: {
    text: {
      type: String
    },
    // 限制高度
    height: {
      type: Number
    },
    // 限制行数，将换算为 height。如果设置了 height，则直接使用 height 计算
    lines: {
      type: Number,
    },
    // 按照指定长度截取
    length: {
      type: Number,
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    // 是否开启 tooltip
    tooltip: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      oversize: false,
      computedReady: false, // 先隐形计算，计算好后，再根据配置显示
      computedText: "", // 计算后的 text 内容
    }
  },
  watch: {
    disabled() {
      this.init();
    },
    text() {
      this.init();
    },
    height() {
      this.init();
    },
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      if (!this.disabled) {
        this.computeText();
        this.limitShow();
      }
    },
    computeText() {
      this.oversize = false;
      this.computedReady = false;

      this.$nextTick(() => {
        let $text = this.$refs.text;
        let $el = this.$el;
        let $more = this.$refs.more;
        let n = 1000;
        let text = this.text;
        let height = this.height;
        // 当 height 未定义，且 lines 定义时，计算真实高度，否则使用 this.height
        if (!height && this.lines) {
          const lineHeight = parseInt(this.getStyle($el, "lineHeight"), 10);
          height = lineHeight * this.lines;
        }

        if ($text) {
          // 指定 length，则按具体字数剪裁
          if (this.length) {
            const textLength = this.fullWidthRecognition
              ? getStrFullLength(text)
              : text.length;
            if (textLength > this.length) {
              this.oversize = true;
              $more.style.display = "inline-block";
              text = this.fullWidthRecognition
                ? cutStrByFullLength(text, this.length)
                : text.slice(0, this.length);
            }
          } else {
            if ($el.offsetHeight > height) {
              this.oversize = true;
              $more.style.display = "inline-block";

              while ($el.offsetHeight > height && n > 0) {
                if ($el.offsetHeight > height * 3) {
                  $text.innerText = text = text.substring(
                    0,
                    Math.floor(text.length / 2)
                  );
                } else {
                  $text.innerText = text = text.substring(0, text.length - 1);
                }
                n--;
              }
            }
          }
        }

        this.computedText = text;
      });
    },
    limitShow() {
      this.computedReady = true;

      this.$nextTick(() => {
        let $text = this.$refs.text;
        let $el = this.$el;

        if ($text) {
          $text.innerText = this.computedText;
          if ($el.offsetHeight > this.height) {
            this.$emit("on-hide");
          } else {
            this.$emit("on-show");
          }
        }
      });
    },
    getStyle (element, styleName) {
      if (!element || !styleName) return null;
      styleName = this.camelCase(styleName);
      try {
        const computed = document.defaultView.getComputedStyle(element, '');
        return element.style[styleName] || computed ? computed[styleName] : null;
      } catch(e) {
        return element.style[styleName];
      }
    },
    camelCase(name) {
      const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
      const MOZ_HACK_REGEXP = /^moz([A-Z])/;
      return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
        return offset ? letter.toUpperCase() : letter;
      }).replace(MOZ_HACK_REGEXP, 'Moz$1');
    }
  }
}
</script>
