<template>
  <div class="xb-backtop" @click.stop="handleClick">
    <div class="xb-backtop-init">
      <i :class="icon" v-if="icon"></i>
      <div class="xb-backtop-text">
        <slot></slot>
      </div>
    </div>
    <div class="xb-backtop-hidden" v-if="text">
      <i :class="icon" v-if="icon"></i>
      <div class="xb-backtop-text">{{ text }}</div>
    </div>
  </div>
</template>

<script>
import throttle from 'throttle-debounce/debounce';

const cubic = value => Math.pow(value, 3);
const easeInOutCubic = value => value < 0.5
  ? cubic(value * 2) / 2
  : 1 - cubic((1 - value) * 2) / 2;

export default {
  name: 'XbBacktop',

  props: {
    text: {
      type: String,
      default: ''
    },
    icon: String,
    backtop: {
      type: Boolean,
      default: false
    },
    visibilityHeight: {
      type: Number,
      default: 200
    },
    target: [String]
  },
  data() {
    return {
      xb: null,
      container: null,
      visible: false
    };
  },

  computed: {

  },

  mounted() {
    this.init();
    this.throttledScrollHandler = throttle(300, this.onScroll);
    this.container.addEventListener('scroll', this.throttledScrollHandler);
  },

  methods: {
    init() {
      this.container = document;
      this.xb = document.documentElement;
      if (this.target) {
        this.xb = document.querySelector(this.target);
        if (!this.xb) {
          throw new Error(`target is not existed: ${this.target}`);
        }
        this.container = this.xb;
      }
    },
    onScroll() {
      const scrollTop = this.xb.scrollTop;
      this.visible = scrollTop >= this.visibilityHeight;
    },
    handleClick(event) {
      if (this.backtop) {
        this.scrollToTop();
        this.$emit('click', event);
      } else if (!this.disabled) {
        if (!this.href) {
          this.$emit('click', event);
        }
      }
    },
    scrollToTop() {
      const xb = this.xb;
      const beginTime = Date.now();
      const beginValue = xb.scrollTop;
      const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16));
      const frameFunc = () => {
        const progress = (Date.now() - beginTime) / 500;
        if (progress < 1) {
          xb.scrollTop = beginValue * (1 - easeInOutCubic(progress));
          rAF(frameFunc);
        } else {
          xb.scrollTop = 0;
        }
      };
      rAF(frameFunc);
    }
  },

  beforeDestroy() {
    this.container.removeEventListener('scroll', this.throttledScrollHandler);
  }
};
</script>