<template>
  <grid-layout
    class="ui-masonry"
    :class="{'is-ready': ready}"
    :col-num="span"
    :margin="margin"
    :row-height="itemHeight"
    :layout.sync="items"
    :vertical-compact="true"
    :use-css-transforms="true"
    :is-draggable="editable"
    :is-resizable="editable"
    @layout-mounted="handleLayoutMounted"
    @layout-ready="handleLayoutReady"
    @layout-updated="handleLayoutUpdated"
  >
    <template v-if="inited">
      <grid-item
        v-for="item in items"
        :key="item.i"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        v-bind="renders[item.i].props"
      >
        <component :is="renders[item.i].render" :data-key="renders[item.i].data.info.count"></component>
      </grid-item>
    </template>
    <slot />
  </grid-layout>
</template>
<script>
import VueGridLayout from 'vue-grid-layout'

export default {
  name: 'UiMasonry',
  components: {
    GridLayout: VueGridLayout.GridLayout,
    GridItem: VueGridLayout.GridItem
  },
  provide() {
    return {
      UiMasonry: this
    }
  },
  props: {
    value: {
      type: Array
    },
    /**
     * 是否可以编辑
    */
    editable: {
      type: Boolean,
      default: false
    },
    /**
     * 水平方向总列数
    */
    span: {
      type: Number,
      default: 8
    },
    /**
     * 单个高度
    */
    itemHeight: {
      type: Number,
      default: 105
    },
    margin: {
      type: Array,
      default() {
        return [0, 0]
      }
    }
  },
  data() {
    return {
      inited: false,
      ready: false,
      items: this.value || [],
      renders: {}
    }
  },
  watch: {
    value() {
      if (this.disabledSyncValue) {
        return
      }
      this.items = this.value || []
    }
  },
  methods: {
    addItem(item, props, data, render) {
      if (!item || !item.i) {
        return
      }
      if (this.items.some(v => v.i === item.i)) {
        return
      }
      this.items.push(item)
      this.renders[item.i] = {
        props,
        data,
        render
      }
      this.submitValue()
    },
    removeItem(i) {
      let index = -1
      this.items.some((v, i) => {
        if (v.i === i) {
          index = i
          return true
        }
      })
      this.items.splice(index, 1)
      delete this.renders[i]
      this.submitValue()
    },
    handleLayoutMounted() {
      this.inited = true
      this.submitValue()
    },
    handleLayoutReady() {
      this.ready = true
    },
    handleLayoutUpdated() {
      if (!this.ready) {
        return
      }
      this.submitValue()
      this.$emit('change')
    },
    submitValue() {
      if (!this.ready) {
        return
      }
      this.disabledSyncValue = true
      this.$emit('input', this.items)
      this.$nextTick(() => {
        this.disabledSyncValue = false
      })
    }
  }
}
</script>
<style lang="less">
.ui-masonry {
  &:not(.is-ready) {
    .vue-grid-item.cssTransforms{
      transition: none!important;
    }
  }
  .vue-grid-item.vue-grid-placeholder{
    background-color: rgba(0,0,0,.03);
    opacity: 1;
  }
  .vue-grid-item:not(.vue-grid-placeholder) {
    border: 1px solid #eee;
    background-color: #fff;
  }
  .vue-grid-item{
    box-sizing: border-box;
  }
  .vue-grid-item .resizing {
    opacity: 0.9;
  }
  .vue-grid-item .no-drag {
    height: 100%;
    width: 100%;
  }
  .vue-draggable-handle {
    position: absolute;
    width: 20px;
    height: 20px;
    top: 0;
    left: 0;
    background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>") no-repeat;
    background-position: bottom right;
    padding: 0 8px 8px 0;
    background-repeat: no-repeat;
    background-origin: content-box;
    box-sizing: border-box;
    cursor: pointer;
  }
}
</style>
