<script>
import draggable from 'vuedraggable'

// 兼容IE的 测试css选择器匹配
function matchesSelector(node, selector) {
  if (node.matches) return node.matches(selector)
  else return node.msMatchesSelector(selector)
}

/**
 * <p>拖拽排序组件。包装 Vue.Draggable，增加动画效果和占位符效果</p>
 * <p>具体参数请参考 https://github.com/SortableJS/Vue.Draggable</p>
 * @displayName SdDraggable 拖拽排序
 * @since 8.0.4
 */
export default {
  name: 'SdDraggable',
  components: {
    draggable,
  },
  inheritAttrs: false,
  props: {
    /**
     * 禁用排序功能，会渲染成一般的组件
     */
    disabled: {
      type: Boolean,
      default: false,
    },
    /**
     * 可拖拽部分鼠标悬停的title
     */
    title: {
      type: String,
      default: '可拖拽排序',
    },
  },
  data() {
    return {
      isDragging: false,
    }
  },
  methods: {},
  render(h) {
    if (this.disabled) {
      const tag = this.$attrs.tag || 'div'

      return (
        <tag
          attrs={this.$attrs['component-data']?.attrs}
          props={this.$attrs['component-data']?.props}
          on={this.$attrs['component-data']?.on}
        >
          {this.$slots.default}
        </tag>
      )
    }
    const { end, start, ...listeners } = this.$listeners

    this.$nextTick(() =>
      this.$slots.default?.forEach((vnode) => {
        const domNode = vnode.elm

        if (
          domNode &&
          (!this.$attrs.draggable || // 没指定哪些可以拖拽，就是都可以拖拽
            matchesSelector(domNode, this.$attrs.draggable)) // 指定了，只有匹配选择器的才可以拖拽
        ) {
          domNode.classList?.add(this.$style.item)
          let handle
          if (this.$attrs.handle) {
            if (matchesSelector(domNode, this.$attrs.handle)) {
              handle = domNode
            } else {
              handle = domNode.querySelector(this.$attrs.handle)
            }
          } else {
            // 没指定handle，整个item作为handle
            handle = domNode
          }
          if (handle) {
            if (this.title) handle.title = this.title
            handle.classList?.add(this.$style.handle)
          }
        }
      })
    )

    return (
      <draggable
        {...{
          attrs: {
            animation: 200, // 默认带动画
            ghostClass: 'sd-drag-ghost', // 默认有个占位符的效果
            swapThreshold: 0.5, // 默认把拖拽区域搞小一点，避免来回闪动
            ...this.$attrs,
          },
          on: {
            start: (...args) => {
              this.isDragging = true
              // 不想出现在文档里，把$emit拆开
              this['$' + 'emit']('start', ...args)
            },
            end: (...args) => {
              this.isDragging = false
              // 不想出现在文档里，把$emit拆开
              this['$' + 'emit']('end', ...args)
            },
            ...listeners,
          },
          nativeOn: {
            drop: (evt) => {
              // 防止firefox拖拽时弹新窗口
              evt.stopPropagation()
              evt.preventDefault()
            },
          },
          scopedSlots: this.$scopedSlots,
          class: {
            [this.$style.wapper]: true,
            'sd-dragging': this.isDragging,
            [this.$style.canPut]: this.$attrs.group?.put !== false,
          },
        }}
      >
        {this.$slots.default}
      </draggable>
    )
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.wapper {
  :global(.sd-drag-ghost) {
    /* stylelint-disable-next-line plugin/no-unsupported-browser-features */
    outline: 1px dashed $primary-5;
    /* stylelint-disable-next-line plugin/no-unsupported-browser-features */
    outline-offset: -1px;
  }
  &:global(.sd-dragging) {
    .item {
      transition: none;
    }
  }
}
.can-put:empty {
  min-height: 32px;
}

// 为了优先级足够高，覆盖ant-design的光标
:global(#sd-body) {
  .handle {
    cursor: move;
  }
}
</style>
