<template>
    <div>
        <div ref="point" :class="{ 'el-affix': affix }" :style="styles">
            <slot></slot>
        </div>
        <div v-show="slot" :style="slotStyle"></div>
    </div>
</template>
<script>
    import { on, off } from 'element-ui/src/utils/dom';

    function getScroll(target, top) {
      const prop = top ? 'pageYOffset' : 'pageXOffset';
      const method = top ? 'scrollTop' : 'scrollLeft';

      let ret = target[prop];

      if (typeof ret !== 'number') {
        ret = target[method];
      }

      return ret;
    }

    function getOffset(element, scrollDom) {
      const rect = element.getBoundingClientRect();

      const scrollTop = getScroll(scrollDom, true);
      const scrollLeft = getScroll(scrollDom);

      const clientTop = scrollDom.clientTop || 0;
      const clientLeft = scrollDom.clientLeft || 0;

      return {
        top: rect.top + scrollTop - clientTop,
        left: rect.left + scrollLeft - clientLeft
      };
    }

    export default {
      name: 'ElAffix',
      props: {
        offsetTop: {
          type: Number,
          default: 0
        },
        offsetBottom: {
          type: Number
        },
        fixed: {
          type: Boolean,
          default: false
        }
      },
      data() {
        return {
          affix: false,
          styles: {},
          slot: false,
          slotStyle: {},
          scrollDom: window
        };
      },
      computed: {
        offsetType() {
          let type = 'top';
          if (this.offsetBottom >= 0) {
            type = 'bottom';
          }

          return type;
        }
      },
      mounted() {
        on(window, 'resize', this.handleScroll);
      },
      beforeDestroy() {
        off(this.scrollDom, 'scroll', this.handleScroll);
        off(window, 'resize', this.handleScroll);
      },
      methods: {
        bind(scrollDom) {
          if (this.fixed) {
            this.handleScroll();
            return ;
          }
          this.scrollDom = scrollDom;
          on(this.scrollDom, 'scroll', this.handleScroll);
        },
        handleScroll() {
          const affix = this.affix;
          const scrollTop = getScroll(this.scrollDom, true);
          const elOffset = getOffset(this.$el, this.scrollDom);
          const windowHeight = window.innerHeight;
          const elHeight = this.$el.getElementsByTagName('div')[0].offsetHeight;

          if (this.fixed) {
            if (this.offsetType === 'top') {
              this.affix = true;
              this.slotStyle = {
                width: this.$refs.point.clientWidth + 'px',
                height: this.$refs.point.clientHeight + 'px'
              };
              this.slot = true;
              this.styles = {
                top: `${this.offsetTop}px`,
                left: `${elOffset.left}px`,
                width: `${this.$el.offsetWidth}px`
              };
            }
            if (this.offsetType === 'bottom') {
              this.affix = true;
              this.styles = {
                bottom: `${this.offsetBottom}px`,
                left: `${elOffset.left}px`,
                width: `${this.$el.offsetWidth}px`
              };
            }
            return ;
          }

          // Fixed Top
          if ((elOffset.top - this.offsetTop) < scrollTop && this.offsetType === 'top' && !affix) {
            this.affix = true;
            this.slotStyle = {
              width: this.$refs.point.clientWidth + 'px',
              height: this.$refs.point.clientHeight + 'px'
            };
            this.slot = true;
            this.styles = {
              top: `${this.offsetTop}px`,
              left: `${elOffset.left}px`,
              width: `${this.$el.offsetWidth}px`
            };

            this.$emit('on-change', true);
          } else if ((elOffset.top - this.offsetTop) > scrollTop && this.offsetType === 'top' && affix) {
            this.slot = false;
            this.slotStyle = {};
            this.affix = false;
            this.styles = null;

            this.$emit('on-change', false);
          }

          // Fixed Bottom
          if ((elOffset.top + this.offsetBottom + elHeight) > (scrollTop + windowHeight) && this.offsetType === 'bottom' && !affix) {
            this.affix = true;
            this.styles = {
              bottom: `${this.offsetBottom}px`,
              left: `${elOffset.left}px`,
              width: `${this.$el.offsetWidth}px`
            };

            this.$emit('on-change', true);
          } else if ((elOffset.top + this.offsetBottom + elHeight) < (scrollTop + windowHeight) && this.offsetType === 'bottom' && affix) {
            this.affix = false;
            this.styles = null;

            this.$emit('on-change', false);
          }
        }
      }
    };
</script>
