chore(h5): swiper navigation click event stopPropagation

<script>
import touchtrack from 'uni-mixins/touchtrack'
import { deepClone } from 'uni-shared'

export default {
  name: 'Swiper',
  mixins: [touchtrack],
  props: {
    indicatorDots: {
      type: [Boolean, String],
      default: false
    },
    vertical: {
      type: [Boolean, String],
      default: false
    },
    autoplay: {
      type: [Boolean, String],
      default: false
    },
    circular: {
      type: [Boolean, String],
      default: false
    },
    interval: {
      type: [Number, String],
      default: 5e3
    },
    duration: {
      type: [Number, String],
      default: 500
    },
    current: {
      type: [Number, String],
      default: 0
    },
    indicatorColor: {
      type: String,
      default: ''
    },
    indicatorActiveColor: {
      type: String,
      default: ''
    },
    previousMargin: {
      type: String,
      default: ''
    },
    nextMargin: {
      type: String,
      default: ''
    },
    currentItemId: {
      type: String,
      default: ''
    },
    skipHiddenItemLayout: {
      type: [Boolean, String],
      default: false
    },
    displayMultipleItems: {
      type: [Number, String],
      default: 1
    },
    disableTouch: {
      type: [Boolean, String],
      default: false
    },
    navigation: {
      type: [Boolean, String],
      default: false
    },
    navigationColor: {
      type: String,
      default: '#fff'
    },
    navigationActiveColor: {
      type: String,
      default: 'rgba(53, 53, 53, 0.6)'
    }
  },
  data () {
    return {
      currentSync: Math.round(this.current) || 0,
      currentItemIdSync: this.currentItemId || '',
      userTracking: false,
      currentChangeSource: '',
      items: [],

      isNavigationAuto: false,
      hideNavigation: false,
      prevDisabled: false,
      nextDisabled: false
    }
  },
  computed: {
    intervalNumber () {
      const interval = Number(this.interval)
      return isNaN(interval) ? 5e3 : interval
    },
    durationNumber () {
      const duration = Number(this.duration)
      return isNaN(duration) ? 500 : duration
    },
    displayMultipleItemsNumber () {
      const displayMultipleItems = Math.round(this.displayMultipleItems)
      return isNaN(displayMultipleItems) ? 1 : displayMultipleItems
    },
    slidesStyle () {
      var style = {}
      if (this.nextMargin || this.previousMargin) {
        style = this.vertical ? {
          left: 0,
          right: 0,
          top: this._upx2px(this.previousMargin),
          bottom: this._upx2px(this.nextMargin)
        } : {
          top: 0,
          bottom: 0,
          left: this._upx2px(this.previousMargin),
          right: this._upx2px(this.nextMargin)
        }
      }
      return style
    },
    slideFrameStyle () {
      var value = Math.abs(100 / this.displayMultipleItemsNumber) + '%'
      return {
        width: this.vertical ? '100%' : value,
        height: !this.vertical ? '100%' : value
      }
    },
    swiperEnabled () {
      return this.items.length > this.displayMultipleItemsNumber
    },
    circularEnabled () {
      return this.circular && this.swiperEnabled
    }
  },
  watch: {
    vertical () {
      this._resetLayout()
    },
    circular () {
      this._resetLayout()
    },
    intervalNumber (val) {
      if (this._timer) {
        this._cancelSchedule()
        this._scheduleAutoplay()
      }
    },
    current (val) {
      this._currentCheck()
    },
    currentSync (val, oldVal) {
      this._currentChanged(val, oldVal)
      this.$emit('update:current', val)
      this._setNavigationState()
    },
    currentItemId (val) {
      this._currentCheck()
    },
    currentItemIdSync (val) {
      this.$emit('update:currentItemId', val)
    },
    displayMultipleItemsNumber () {
      this._resetLayout()
    },
    navigation (val) {
      this.isNavigationAuto = val === 'auto'
      this.hideNavigation = val !== true || this.isNavigationAuto
      this._navigationSwiperAddMouseEvent()
    },
    items () {
      this._setNavigationState()
    },
    swiperEnabled (val) {
      if (!val) {
        this.prevDisabled = true
        this.nextDisabled = true
        this.isNavigationAuto && (this.hideNavigation = true)
      }
    }
  },
  created () {
    this._invalid = true
    this._viewportPosition = 0
    this._viewportMoveRatio = 1
    this._animating = null
    this._requestedAnimation = false
    this._userDirectionChecked = false
    this._contentTrackViewport = 0
    this._contentTrackSpeed = 0
    this._contentTrackT = 0
  },
  mounted () {
    this._currentCheck()
    this.touchtrack(this.$refs.slidesWrapper, '_handleContentTrack', true)
    this._resetLayout()
    this.$watch(() => {
      return this.autoplay && !this.userTracking
    }, this._inintAutoplay)
    this._inintAutoplay(this.autoplay && !this.userTracking)
    this.$watch('items.length', this._resetLayout)
    this._navigationSwiperAddMouseEvent()
  },
  beforeDestroy () {
    this._cancelSchedule()
    cancelAnimationFrame(this._animationFrame)
  },
  methods: {
    _inintAutoplay (enable) {
      if (enable) {
        this._scheduleAutoplay()
      } else {
        this._cancelSchedule()
      }
    },
    /**
     * 页面变更检查和同步
     */
    _currentCheck () {
      var current = -1
      if (this.currentItemId) {
        for (let i = 0, items = this.items; i < items.length; i++) {
          const componentInstance = items[i].componentInstance
          if (componentInstance && componentInstance.itemId === this.currentItemId) {
            current = i
            break
          }
        }
      }
      if (current < 0) {
        current = Math.round(this.current) || 0
      }
      current = current < 0 ? 0 : current
      if (this.currentSync !== current) {
        this.currentChangeSource = ''
        this.currentSync = current
      }
    },
    _itemReady (vnode, callback) {
      if (vnode.componentInstance && vnode.componentInstance._isMounted) {
        callback()
      } else {
        vnode._callbacks = vnode._callbacks || []
        vnode._callbacks.push(callback)
      }
    },
    /**
     * 当前页面变更
     */
    _currentChanged (current, history) {
      var source = this.currentChangeSource
      this.currentChangeSource = ''
      if (!source) {
        const length = this.items.length
        this._animateViewport(current, '', this.circularEnabled && history + (length - current) % length > length / 2 ? 1 : 0)
      }
      var item = this.items[current]
      if (item) {
        this._itemReady(item, () => {
          var currentItemId = this.currentItemIdSync = item.componentInstance.itemId || ''
          this.$trigger('change', {}, {
            current: this.currentSync,
            currentItemId,
            source
          })
        })
      }
    },
    /**
     * 自动播放
     */
    _scheduleAutoplay () {
      var self = this
      this._cancelSchedule()
      function timer () {
        self._timer = null
        self.currentChangeSource = 'autoplay'
        if (self.circularEnabled) {
          self.currentSync = self._normalizeCurrentValue(self.currentSync + 1)
        } else {
          self.currentSync = self.currentSync + self.displayMultipleItemsNumber < self.items.length ? self.currentSync + 1 : 0
        }
        self._animateViewport(self.currentSync, 'autoplay', self.circularEnabled ? 1 : 0)
        self._timer = setTimeout(timer, self.intervalNumber)
      }
      if (!(!this._isMounted || this._invalid || this.items.length <= this.displayMultipleItemsNumber)) {
        this._timer = setTimeout(timer, this.intervalNumber)
      }
    },
    /**
     * 清除定时器
     */
    _cancelSchedule () {
      if (this._timer) {
        clearTimeout(this._timer)
        this._timer = null
      }
    },
    /**
     * 检查当前页值
     */
    _normalizeCurrentValue (current) {
      var length = this.items.length
      if (!length) {
        return -1
      }
      var index = (Math.round(current) % length + length) % length
      if (this.circularEnabled) {
        if (length <= this.displayMultipleItemsNumber) {
          return 0
        }
      } else if (index > length - this.displayMultipleItemsNumber) {
        return length - this.displayMultipleItemsNumber
      }
      return index
    },
    _upx2px (val) {
      if (/\d+[ur]px$/i.test(val)) {
        val.replace(/\d+[ur]px$/i, text => {
          return `${uni.upx2px(parseFloat(text))}px`
        })
      }
      return val || ''
    },
    /**
     * 重新布局
     */
    _resetLayout () {
      if (this._isMounted) {
        this._cancelSchedule()
        this._endViewportAnimation()
        var items = this.items

        for (var i = 0; i < items.length; i++) {
          this._updateItemPos(i, i)
        }
        this._viewportMoveRatio = 1
        if (this.displayMultipleItemsNumber === 1 && items.length) {
          var itemRect = items[0].componentInstance.$el.getBoundingClientRect()
          var slideFrameRect = this.$refs.slideFrame.getBoundingClientRect()
          this._viewportMoveRatio = itemRect.width / slideFrameRect.width
          if (!(this._viewportMoveRatio > 0 && this._viewportMoveRatio < 1)) {
            this._viewportMoveRatio = 1
          }
        }
        var position = this._viewportPosition
        this._viewportPosition = -2
        var current = this.currentSync
        if (current >= 0) {
          this._invalid = false
          if (this.userTracking) {
            this._updateViewport(position + current - this._contentTrackViewport)
            this._contentTrackViewport = current
          } else {
            this._updateViewport(current)
            if (this.autoplay) {
              this._scheduleAutoplay()
            }
          }
        } else {
          this._invalid = true
          this._updateViewport(-this.displayMultipleItemsNumber - 1)
        }
      }
    },
    _checkCircularLayout (e) {
      if (!this._invalid) {
        for (var items = this.items, n = items.length, i = e + this.displayMultipleItemsNumber, r = 0; r < n; r++) {
          var item = items[r]
          var _position = item._position
          var s = Math.floor(e / n) * n + r
          var l = s + n
          var c = s - n
          var u = Math.max(e - (s + 1), s - i, 0)
          var d = Math.max(e - (l + 1), l - i, 0)
          var h = Math.max(e - (c + 1), c - i, 0)
          var p = Math.min(u, d, h)
          var f = [s, l, c][[u, d, h].indexOf(p)]
          if (_position !== f) {
            this._updateItemPos(r, f)
          }
        }
      }
    },
    _updateItemPos (current, position) {
      var x = this.vertical ? '0' : 100 * position + '%'
      var y = this.vertical ? 100 * position + '%' : '0'
      var transform = 'translate(' + x + ', ' + y + ') translateZ(0)'
      var item = this.items[current]
      this._itemReady(item, () => {
        var el = item.componentInstance.$el
        el.style['-webkit-transform'] = transform
        el.style.transform = transform
        el._position = position
      })
    },
    _updateViewport (index) {
      if (!(Math.floor(2 * this._viewportPosition) === Math.floor(2 * index) && Math.ceil(2 * this._viewportPosition) === Math.ceil(2 * index))) {
        if (this.circularEnabled) {
          this._checkCircularLayout(index)
        }
      }

      var x = this.vertical ? '0' : 100 * -index * this._viewportMoveRatio + '%'
      var y = this.vertical ? 100 * -index * this._viewportMoveRatio + '%' : '0'
      var transform = 'translate(' + x + ', ' + y + ') translateZ(0)'
      var slideFrame = this.$refs.slideFrame
      if (slideFrame) {
        slideFrame.style['-webkit-transform'] = transform
        slideFrame.style.transform = transform
      }
      this._viewportPosition = index
      if (!this._transitionStart) {
        if (index % 1 === 0) {
          return
        }
        this._transitionStart = index
      }
      index -= Math.floor(this._transitionStart)
      if (index <= -(this.items.length - 1)) {
        index += this.items.length
      } else if (index >= this.items.length) {
        index -= this.items.length
      }
      index = this._transitionStart % 1 > 0.5 || this._transitionStart < 0 ? index - 1 : index
      this.$trigger('transition', {}, {
        dx: this.vertical ? 0 : index * slideFrame.offsetWidth,
        dy: this.vertical ? index * slideFrame.offsetHeight : 0
      })
    },
    _animateFrameFuncProto () {
      if (!this._animating) {
        this._requestedAnimation = false
        return
      }
      var _animating = this._animating
      var toPos = _animating.toPos
      var acc = _animating.acc
      var endTime = _animating.endTime
      var source = _animating.source
      var time = endTime - Date.now()
      if (time <= 0) {
        this._updateViewport(toPos)
        this._animating = null
        this._requestedAnimation = false
        this._transitionStart = null
        var item = this.items[this.currentSync]
        if (item) {
          this._itemReady(item, () => {
            var currentItemId = item.componentInstance.itemId || ''
            this.$trigger('animationfinish', {}, {
              current: this.currentSync,
              currentItemId,
              source
            })
          })
        }
        return
      }
      var s = acc * time * time / 2
      var l = toPos + s
      this._updateViewport(l)
      this._animationFrame = requestAnimationFrame(this._animateFrameFuncProto.bind(this))
    },
    _animateViewport (current, source, n) {
      this._cancelViewportAnimation()
      var duration = this.durationNumber
      var length = this.items.length
      var position = this._viewportPosition
      if (this.circularEnabled) {
        if (n < 0) {
          for (; position < current;) {
            position += length
          }
          for (; position - length > current;) {
            position -= length
          }
        } else if (n > 0) {
          for (; position > current;) {
            position -= length
          }
          for (; position + length < current;) {
            position += length
          }
          if (position + length - current < current - position) {
            position += length
          }
        } else {
          for (; position + length < current;) {
            position += length
          }
          for (; position - length > current;) {
            position -= length
          }
          if (position + length - current < current - position) {
            position += length
          }
        }
      } else if (source === 'click') {
        current = current + this.displayMultipleItemsNumber - 1 < length ? current : 0
      }

      this._animating = {
        toPos: current,
        acc: 2 * (position - current) / (duration * duration),
        endTime: Date.now() + duration,
        source: source
      }
      if (!this._requestedAnimation) {
        this._requestedAnimation = true
        this._animationFrame = requestAnimationFrame(this._animateFrameFuncProto.bind(this))
      }
    },
    _cancelViewportAnimation () {
      this._animating = null
    },
    /**
     * 结束动画
     */
    _endViewportAnimation () {
      if (this._animating) {
        this._updateViewport(this._animating.toPos)
        this._animating = null
      }
    },
    _handleTrackStart () {
      this._cancelSchedule()
      this._contentTrackViewport = this._viewportPosition
      this._contentTrackSpeed = 0
      this._contentTrackT = Date.now()
      this._cancelViewportAnimation()
    },
    _handleTrackMove (data) {
      var self = this
      var contentTrackT = this._contentTrackT
      this._contentTrackT = Date.now()
      var length = this.items.length
      var other = length - this.displayMultipleItemsNumber
      function calc (val) {
        return 0.5 - 0.25 / (val + 0.5)
      }

      function move (oldVal, newVal) {
        var val = self._contentTrackViewport + oldVal
        self._contentTrackSpeed = 0.6 * self._contentTrackSpeed + 0.4 * newVal
        if (!self.circularEnabled) {
          if (val < 0 || val > other) {
            if (val < 0) {
              val = -calc(-val)
            } else {
              if (val > other) {
                val = other + calc(val - other)
              }
            }
            self._contentTrackSpeed = 0
          }
        }
        self._updateViewport(val)
      }
      var time = (this._contentTrackT - contentTrackT) || 1
      if (this.vertical) {
        move(-data.dy / this.$refs.slideFrame.offsetHeight, -data.ddy / time)
      } else {
        move(-data.dx / this.$refs.slideFrame.offsetWidth, -data.ddx / time)
      }
    },
    _handleTrackEnd (isCancel) {
      this.userTracking = false
      var t = this._contentTrackSpeed / Math.abs(this._contentTrackSpeed)
      var n = 0
      if (!isCancel && Math.abs(this._contentTrackSpeed) > 0.2) {
        n = 0.5 * t
      }
      var current = this._normalizeCurrentValue(this._viewportPosition + n)
      if (isCancel) {
        this._updateViewport(this._contentTrackViewport)
      } else {
        this.currentChangeSource = 'touch'
        this.currentSync = current
        this._animateViewport(current, 'touch', n !== 0 ? n : current === 0 && (this.circularEnabled && this._viewportPosition >= 1) ? 1 : 0)
      }
    },
    _handleContentTrack (e) {
      if (this.disableTouch || !this.items.length) {
        return
      }
      if (!this._invalid) {
        if (e.detail.state === 'start') {
          this.userTracking = true
          this._userDirectionChecked = false
          return this._handleTrackStart()
        }
        // fixed by xxxxxx
        if (e.detail.state === 'end') {
          return this._handleTrackEnd(false)
        }
        if (e.detail.state === 'cancel') {
          return this._handleTrackEnd(true)
        }
        if (this.userTracking) {
          if (!this._userDirectionChecked) {
            this._userDirectionChecked = true
            var t = Math.abs(e.detail.dx)
            var n = Math.abs(e.detail.dy)
            if (t >= n && this.vertical) {
              this.userTracking = false
            } else {
              if (t <= n && !this.vertical) {
                this.userTracking = false
              }
            }
            if (!this.userTracking) {
              if (this.autoplay) {
                this._scheduleAutoplay()
              }
              return
            }
          }
          this._handleTrackMove(e.detail)
          return false
        }
      }
    },
    /**
     * navigation
     */
    _onSwiperDotClick (index) {
      this._animateViewport(
        (this.currentSync = index),
        (this.currentChangeSource = 'click'),
        this.circularEnabled ? 1 : 0
      )
    },
    _navigationClick ($event, type) {
      $event.stopPropagation()

      const swiperItemLength = this.items.length
      let _current = this.currentSync

      switch (type) {
        case 'prev':
          _current--
          if (_current < 0 && this.circularEnabled) {
            _current = swiperItemLength - 1
          }
          break
        case 'next':
          _current++
          if (_current >= swiperItemLength && this.circularEnabled) {
            _current = 0
          }
          break
      }

      this._onSwiperDotClick(_current)
    },
    _navigationMouseMove (e) {
      const { clientX, clientY } = e
      const {
        left,
        right,
        top,
        bottom,
        width,
        height
      } = this.$refs.slidesWrapper.getBoundingClientRect()

      if (this.vertical) {
        this.hideNavigation = !(
          clientY - top < height / 3 || bottom - clientY < height / 3
        )
      } else {
        this.hideNavigation = !(
          clientX - left < width / 3 || right - clientX < width / 3
        )
      }
    },
    _navigationMouseOut () {
      this.hideNavigation = true
    },
    _navigationSwiperAddMouseEvent () {
      if (__PLATFORM__ === 'h5') {
        const rootRef = this.$refs.slidesWrapper
        if (rootRef) {
          rootRef.removeEventListener('mousemove', this._navigationMouseMove)
          rootRef.removeEventListener('mouseout', this._navigationMouseOut)

          if (this.isNavigationAuto) {
            rootRef.addEventListener('mousemove', this._navigationMouseMove)
            rootRef.addEventListener('mouseout', this._navigationMouseOut)
          }
        }
      }
    },
    _navigationHover (event, type) {
      const target = event.currentTarget
      if (!target) return
      target.style.backgroundColor =
        type === 'over' ? this.navigationActiveColor : ''
    },
    _setNavigationState () {
      const swiperItemLength = this.items.length
      const notCircular = !this.circularEnabled

      this.prevDisabled = this.currentSync === 0 && notCircular
      this.nextDisabled =
        (this.currentSync === swiperItemLength - 1 && notCircular) ||
        (notCircular &&
          this.currentSync + this.displayMultipleItemsNumber >= swiperItemLength)
    }
  },
  render (createElement) {
    var slidesDots = []
    var swiperItems = []
    if (this.$slots.default) {
      deepClone(this.$slots.default, createElement).forEach(vnode => {
        if (vnode.componentOptions && vnode.componentOptions.tag === 'v-uni-swiper-item') {
          swiperItems.push(vnode)
        }
      })
    }
    for (let index = 0, length = swiperItems.length; index < length; index++) {
      const currentSync = this.currentSync
      slidesDots.push(createElement('div', {
        on: {
          click: () => this._onSwiperDotClick(index)
        },
        class: {
          'uni-swiper-dot': true,
          'uni-swiper-dot-active': (index < currentSync + this.displayMultipleItemsNumber && index >= currentSync) || (index < currentSync + this.displayMultipleItemsNumber - length)
        },
        style: {
          background: index === currentSync ? this.indicatorActiveColor : this.indicatorColor
        }
      }))
    }
    this.items = swiperItems
    var slidesWrapperChild = [createElement('div', {
      ref: 'slides',
      style: this.slidesStyle,
      class: 'uni-swiper-slides'
    }, [
      createElement('div', {
        ref: 'slideFrame',
        class: 'uni-swiper-slide-frame',
        style: this.slideFrameStyle
      }, swiperItems)
    ])]
    if (this.indicatorDots) {
      slidesWrapperChild.push(createElement('div', {
        ref: 'slidesDots',
        class: ['uni-swiper-dots', this.vertical ? 'uni-swiper-dots-vertical' : 'uni-swiper-dots-horizontal']
      }, slidesDots))
    }

    if (__PLATFORM__ === 'h5') {
      if (this.navigation) {
        const navigationClass = {
          'uni-swiper-navigation-hide': this.hideNavigation,
          'uni-swiper-navigation-vertical': this.vertical
        }

        const iconElement = createElement(
          'i',
          {
            domProps: {
              innerHTML: ''
            },
            class: 'uni-btn-icon',
            style: { color: this.navigationColor, fontSize: '26px' }
          }
        )

        const navigationEvent = {
          mouseover: event => this._navigationHover(event, 'over'),
          mouseout: event => this._navigationHover(event, 'out')
        }

        slidesWrapperChild.push(
          createElement(
            'div',
            {
              on: {
                click: (e) => this._navigationClick(e, 'prev'),
                ...navigationEvent
              },
              class: [
                'uni-swiper-navigation',
                'uni-swiper-navigation-prev',
                {
                  'uni-swiper-navigation-disabled': this.prevDisabled,
                  ...navigationClass
                }
              ]
            },
            [iconElement]
          ),
          createElement(
            'div',
            {
              on: {
                click: (e) => this._navigationClick(e, 'next'),
                ...navigationEvent
              },
              class: [
                'uni-swiper-navigation',
                'uni-swiper-navigation-next',
                {
                  'uni-swiper-navigation-disabled': this.nextDisabled,
                  ...navigationClass
                }
              ]
            },
            [iconElement]
          )
        )
      }
    }

    return createElement(
      'uni-swiper', {
        on: this.$listeners
      }, [createElement('div', {
        ref: 'slidesWrapper',
        class: 'uni-swiper-wrapper'
      }, slidesWrapperChild)]
    )
  }
}
</script>
<style>
uni-swiper {
  display: block;
  height: 150px;
}

uni-swiper[hidden] {
  display: none;
}

uni-swiper .uni-swiper-wrapper {
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 100%;
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
}

uni-swiper .uni-swiper-slides {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

uni-swiper .uni-swiper-slide-frame {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  will-change: transform;
}

uni-swiper .uni-swiper-dots {
  position: absolute;
  font-size: 0;
}

uni-swiper .uni-swiper-dots-horizontal {
  left: 50%;
  bottom: 10px;
  text-align: center;
  white-space: nowrap;
  -webkit-transform: translate(-50%, 0);
  transform: translate(-50%, 0);
}

uni-swiper .uni-swiper-dots-horizontal .uni-swiper-dot {
  margin-right: 8px;
}

uni-swiper .uni-swiper-dots-horizontal .uni-swiper-dot:last-child {
  margin-right: 0;
}

uni-swiper .uni-swiper-dots-vertical {
  right: 10px;
  top: 50%;
  text-align: right;
  -webkit-transform: translate(0, -50%);
  transform: translate(0, -50%);
}

uni-swiper .uni-swiper-dots-vertical .uni-swiper-dot {
  display: block;
  margin-bottom: 9px;
}

uni-swiper .uni-swiper-dots-vertical .uni-swiper-dot:last-child {
  margin-bottom: 0;
}

uni-swiper .uni-swiper-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  cursor: pointer;
  transition-property: background-color;
  transition-timing-function: ease;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 50%;
}

uni-swiper .uni-swiper-dot-active {
  background-color: #000000;
}

uni-swiper .uni-swiper-navigation {
  width: 26px;
  height: 26px;
  cursor: pointer;
  position: absolute;
  top: 50%;
  margin-top: -13px;
  display: flex;
  align-items: center;
  transition: all 0.2s;
  border-radius: 50%;
  opacity: 1;
}

uni-swiper .uni-swiper-navigation-disabled {
  opacity: 0.35;
  cursor: auto;
  pointer-events: none;
}

uni-swiper .uni-swiper-navigation-hide {
  opacity: 0;
  cursor: auto;
  pointer-events: none;
}

uni-swiper .uni-swiper-navigation-prev {
  left: 10px;
}

uni-swiper .uni-swiper-navigation-prev i {
  margin-left: -1px;
  left: 10px;
}

uni-swiper .uni-swiper-navigation-prev.uni-swiper-navigation-vertical {
  top: 18px;
  left: 50%;
  margin-left: -13px;
}

uni-swiper .uni-swiper-navigation-prev.uni-swiper-navigation-vertical i {
  transform: rotate(90deg);
  margin-left: auto;
  margin-top: -2px;
}

uni-swiper .uni-swiper-navigation-next {
  right: 10px;
}

uni-swiper .uni-swiper-navigation-next i {
  transform: rotate(180deg);
}

uni-swiper .uni-swiper-navigation-next.uni-swiper-navigation-vertical {
  top: auto;
  bottom: 5px;
  left: 50%;
  margin-left: -13px;
}

uni-swiper .uni-swiper-navigation-next.uni-swiper-navigation-vertical i {
  margin-top: 2px;
  transform: rotate(270deg);
}
</style>

<script>
import touchtrack from 'uni-mixins/touchtrack'
import { deepClone } from 'uni-shared'

export default {
  name: 'Swiper',
  mixins: [touchtrack],
  props: {
    indicatorDots: {
      type: [Boolean, String],
      default: false
    },
    vertical: {
      type: [Boolean, String],
      default: false
    },
    autoplay: {
      type: [Boolean, String],
      default: false
    },
    circular: {
      type: [Boolean, String],
      default: false
    },
    interval: {
      type: [Number, String],
      default: 5e3
    },
    duration: {
      type: [Number, String],
      default: 500
    },
    current: {
      type: [Number, String],
      default: 0
    },
    indicatorColor: {
      type: String,
      default: ''
    },
    indicatorActiveColor: {
      type: String,
      default: ''
    },
    previousMargin: {
      type: String,
      default: ''
    },
    nextMargin: {
      type: String,
      default: ''
    },
    currentItemId: {
      type: String,
      default: ''
    },
    skipHiddenItemLayout: {
      type: [Boolean, String],
      default: false
    },
    displayMultipleItems: {
      type: [Number, String],
      default: 1
    },
    disableTouch: {
      type: [Boolean, String],
      default: false
    },
    navigation: {
      type: [Boolean, String],
      default: false
    },
    navigationColor: {
      type: String,
      default: '#fff'
    },
    navigationActiveColor: {
      type: String,
      default: 'rgba(53, 53, 53, 0.6)'
    }
  },
  data () {
    return {
      currentSync: Math.round(this.current) || 0,
      currentItemIdSync: this.currentItemId || '',
      userTracking: false,
      currentChangeSource: '',
      items: [],

      isNavigationAuto: false,
      hideNavigation: false,
      prevDisabled: false,
      nextDisabled: false
    }
  },
  computed: {
    intervalNumber () {
      const interval = Number(this.interval)
      return isNaN(interval) ? 5e3 : interval
    },
    durationNumber () {
      const duration = Number(this.duration)
      return isNaN(duration) ? 500 : duration
    },
    displayMultipleItemsNumber () {
      const displayMultipleItems = Math.round(this.displayMultipleItems)
      return isNaN(displayMultipleItems) ? 1 : displayMultipleItems
    },
    slidesStyle () {
      var style = {}
      if (this.nextMargin || this.previousMargin) {
        style = this.vertical ? {
          left: 0,
          right: 0,
          top: this._upx2px(this.previousMargin),
          bottom: this._upx2px(this.nextMargin)
        } : {
          top: 0,
          bottom: 0,
          left: this._upx2px(this.previousMargin),
          right: this._upx2px(this.nextMargin)
        }
      }
      return style
    },
    slideFrameStyle () {
      var value = Math.abs(100 / this.displayMultipleItemsNumber) + '%'
      return {
        width: this.vertical ? '100%' : value,
        height: !this.vertical ? '100%' : value
      }
    },
    swiperEnabled () {
      return this.items.length > this.displayMultipleItemsNumber
    },
    circularEnabled () {
      return this.circular && this.swiperEnabled
    }
  },
  watch: {
    vertical () {
      this._resetLayout()
    },
    circular () {
      this._resetLayout()
    },
    intervalNumber (val) {
      if (this._timer) {
        this._cancelSchedule()
        this._scheduleAutoplay()
      }
    },
    current (val) {
      this._currentCheck()
    },
    currentSync (val, oldVal) {
      this._currentChanged(val, oldVal)
      this.$emit('update:current', val)
      this._setNavigationState()
    },
    currentItemId (val) {
      this._currentCheck()
    },
    currentItemIdSync (val) {
      this.$emit('update:currentItemId', val)
    },
    displayMultipleItemsNumber () {
      this._resetLayout()
    },
    navigation (val) {
      this.isNavigationAuto = val === 'auto'
      this.hideNavigation = val !== true || this.isNavigationAuto
      this._navigationSwiperAddMouseEvent()
    },
    items () {
      this._setNavigationState()
    },
    swiperEnabled (val) {
      if (!val) {
        this.prevDisabled = true
        this.nextDisabled = true
        this.isNavigationAuto && (this.hideNavigation = true)
      }
    }
  },
  created () {
    this._invalid = true
    this._viewportPosition = 0
    this._viewportMoveRatio = 1
    this._animating = null
    this._requestedAnimation = false
    this._userDirectionChecked = false
    this._contentTrackViewport = 0
    this._contentTrackSpeed = 0
    this._contentTrackT = 0
  },
  mounted () {
    this._currentCheck()
    this.touchtrack(this.$refs.slidesWrapper, '_handleContentTrack', true)
    this._resetLayout()
    this.$watch(() => {
      return this.autoplay && !this.userTracking
    }, this._inintAutoplay)
    this._inintAutoplay(this.autoplay && !this.userTracking)
    this.$watch('items.length', this._resetLayout)
    this._navigationSwiperAddMouseEvent()
  },
  beforeDestroy () {
    this._cancelSchedule()
    cancelAnimationFrame(this._animationFrame)
  },
  methods: {
    _inintAutoplay (enable) {
      if (enable) {
        this._scheduleAutoplay()
      } else {
        this._cancelSchedule()
      }
    },
    /**
     * 页面变更检查和同步
     */
    _currentCheck () {
      var current = -1
      if (this.currentItemId) {
        for (let i = 0, items = this.items; i < items.length; i++) {
          const componentInstance = items[i].componentInstance
          if (componentInstance && componentInstance.itemId === this.currentItemId) {
            current = i
            break
          }
        }
      }
      if (current < 0) {
        current = Math.round(this.current) || 0
      }
      current = current < 0 ? 0 : current
      if (this.currentSync !== current) {
        this.currentChangeSource = ''
        this.currentSync = current
      }
    },
    _itemReady (vnode, callback) {
      if (vnode.componentInstance && vnode.componentInstance._isMounted) {
        callback()
      } else {
        vnode._callbacks = vnode._callbacks || []
        vnode._callbacks.push(callback)
      }
    },
    /**
     * 当前页面变更
     */
    _currentChanged (current, history) {
      var source = this.currentChangeSource
      this.currentChangeSource = ''
      if (!source) {
        const length = this.items.length
        this._animateViewport(current, '', this.circularEnabled && history + (length - current) % length > length / 2 ? 1 : 0)
      }
      var item = this.items[current]
      if (item) {
        this._itemReady(item, () => {
          var currentItemId = this.currentItemIdSync = item.componentInstance.itemId || ''
          this.$trigger('change', {}, {
            current: this.currentSync,
            currentItemId,
            source
          })
        })
      }
    },
    /**
     * 自动播放
     */
    _scheduleAutoplay () {
      var self = this
      this._cancelSchedule()
      function timer () {
        self._timer = null
        self.currentChangeSource = 'autoplay'
        if (self.circularEnabled) {
          self.currentSync = self._normalizeCurrentValue(self.currentSync + 1)
        } else {
          self.currentSync = self.currentSync + self.displayMultipleItemsNumber < self.items.length ? self.currentSync + 1 : 0
        }
        self._animateViewport(self.currentSync, 'autoplay', self.circularEnabled ? 1 : 0)
        self._timer = setTimeout(timer, self.intervalNumber)
      }
      if (!(!this._isMounted || this._invalid || this.items.length <= this.displayMultipleItemsNumber)) {
        this._timer = setTimeout(timer, this.intervalNumber)
      }
    },
    /**
     * 清除定时器
     */
    _cancelSchedule () {
      if (this._timer) {
        clearTimeout(this._timer)
        this._timer = null
      }
    },
    /**
     * 检查当前页值
     */
    _normalizeCurrentValue (current) {
      var length = this.items.length
      if (!length) {
        return -1
      }
      var index = (Math.round(current) % length + length) % length
      if (this.circularEnabled) {
        if (length <= this.displayMultipleItemsNumber) {
          return 0
        }
      } else if (index > length - this.displayMultipleItemsNumber) {
        return length - this.displayMultipleItemsNumber
      }
      return index
    },
    _upx2px (val) {
      if (/\d+[ur]px$/i.test(val)) {
        val.replace(/\d+[ur]px$/i, text => {
          return `${uni.upx2px(parseFloat(text))}px`
        })
      }
      return val || ''
    },
    /**
     * 重新布局
     */
    _resetLayout () {
      if (this._isMounted) {
        this._cancelSchedule()
        this._endViewportAnimation()
        var items = this.items

        for (var i = 0; i < items.length; i++) {
          this._updateItemPos(i, i)
        }
        this._viewportMoveRatio = 1
        if (this.displayMultipleItemsNumber === 1 && items.length) {
          var itemRect = items[0].componentInstance.$el.getBoundingClientRect()
          var slideFrameRect = this.$refs.slideFrame.getBoundingClientRect()
          this._viewportMoveRatio = itemRect.width / slideFrameRect.width
          if (!(this._viewportMoveRatio > 0 && this._viewportMoveRatio < 1)) {
            this._viewportMoveRatio = 1
          }
        }
        var position = this._viewportPosition
        this._viewportPosition = -2
        var current = this.currentSync
        if (current >= 0) {
          this._invalid = false
          if (this.userTracking) {
            this._updateViewport(position + current - this._contentTrackViewport)
            this._contentTrackViewport = current
          } else {
            this._updateViewport(current)
            if (this.autoplay) {
              this._scheduleAutoplay()
            }
          }
        } else {
          this._invalid = true
          this._updateViewport(-this.displayMultipleItemsNumber - 1)
        }
      }
    },
    _checkCircularLayout (e) {
      if (!this._invalid) {
        for (var items = this.items, n = items.length, i = e + this.displayMultipleItemsNumber, r = 0; r < n; r++) {
          var item = items[r]
          var _position = item._position
          var s = Math.floor(e / n) * n + r
          var l = s + n
          var c = s - n
          var u = Math.max(e - (s + 1), s - i, 0)
          var d = Math.max(e - (l + 1), l - i, 0)
          var h = Math.max(e - (c + 1), c - i, 0)
          var p = Math.min(u, d, h)
          var f = [s, l, c][[u, d, h].indexOf(p)]
          if (_position !== f) {
            this._updateItemPos(r, f)
          }
        }
      }
    },
    _updateItemPos (current, position) {
      var x = this.vertical ? '0' : 100 * position + '%'
      var y = this.vertical ? 100 * position + '%' : '0'
      var transform = 'translate(' + x + ', ' + y + ') translateZ(0)'
      var item = this.items[current]
      this._itemReady(item, () => {
        var el = item.componentInstance.$el
        el.style['-webkit-transform'] = transform
        el.style.transform = transform
        el._position = position
      })
    },
    _updateViewport (index) {
      if (!(Math.floor(2 * this._viewportPosition) === Math.floor(2 * index) && Math.ceil(2 * this._viewportPosition) === Math.ceil(2 * index))) {
        if (this.circularEnabled) {
          this._checkCircularLayout(index)
        }
      }

      var x = this.vertical ? '0' : 100 * -index * this._viewportMoveRatio + '%'
      var y = this.vertical ? 100 * -index * this._viewportMoveRatio + '%' : '0'
      var transform = 'translate(' + x + ', ' + y + ') translateZ(0)'
      var slideFrame = this.$refs.slideFrame
      if (slideFrame) {
        slideFrame.style['-webkit-transform'] = transform
        slideFrame.style.transform = transform
      }
      this._viewportPosition = index
      if (!this._transitionStart) {
        if (index % 1 === 0) {
          return
        }
        this._transitionStart = index
      }
      index -= Math.floor(this._transitionStart)
      if (index <= -(this.items.length - 1)) {
        index += this.items.length
      } else if (index >= this.items.length) {
        index -= this.items.length
      }
      index = this._transitionStart % 1 > 0.5 || this._transitionStart < 0 ? index - 1 : index
      this.$trigger('transition', {}, {
        dx: this.vertical ? 0 : index * slideFrame.offsetWidth,
        dy: this.vertical ? index * slideFrame.offsetHeight : 0
      })
    },
    _animateFrameFuncProto () {
      if (!this._animating) {
        this._requestedAnimation = false
        return
      }
      var _animating = this._animating
      var toPos = _animating.toPos
      var acc = _animating.acc
      var endTime = _animating.endTime
      var source = _animating.source
      var time = endTime - Date.now()
      if (time <= 0) {
        this._updateViewport(toPos)
        this._animating = null
        this._requestedAnimation = false
        this._transitionStart = null
        var item = this.items[this.currentSync]
        if (item) {
          this._itemReady(item, () => {
            var currentItemId = item.componentInstance.itemId || ''
            this.$trigger('animationfinish', {}, {
              current: this.currentSync,
              currentItemId,
              source
            })
          })
        }
        return
      }
      var s = acc * time * time / 2
      var l = toPos + s
      this._updateViewport(l)
      this._animationFrame = requestAnimationFrame(this._animateFrameFuncProto.bind(this))
    },
    _animateViewport (current, source, n) {
      this._cancelViewportAnimation()
      var duration = this.durationNumber
      var length = this.items.length
      var position = this._viewportPosition
      if (this.circularEnabled) {
        if (n < 0) {
          for (; position < current;) {
            position += length
          }
          for (; position - length > current;) {
            position -= length
          }
        } else if (n > 0) {
          for (; position > current;) {
            position -= length
          }
          for (; position + length < current;) {
            position += length
          }
          if (position + length - current < current - position) {
            position += length
          }
        } else {
          for (; position + length < current;) {
            position += length
          }
          for (; position - length > current;) {
            position -= length
          }
          if (position + length - current < current - position) {
            position += length
          }
        }
      } else if (source === 'click') {
        current = current + this.displayMultipleItemsNumber - 1 < length ? current : 0
      }

      this._animating = {
        toPos: current,
        acc: 2 * (position - current) / (duration * duration),
        endTime: Date.now() + duration,
        source: source
      }
      if (!this._requestedAnimation) {
        this._requestedAnimation = true
        this._animationFrame = requestAnimationFrame(this._animateFrameFuncProto.bind(this))
      }
    },
    _cancelViewportAnimation () {
      this._animating = null
    },
    /**
     * 结束动画
     */
    _endViewportAnimation () {
      if (this._animating) {
        this._updateViewport(this._animating.toPos)
        this._animating = null
      }
    },
    _handleTrackStart () {
      this._cancelSchedule()
      this._contentTrackViewport = this._viewportPosition
      this._contentTrackSpeed = 0
      this._contentTrackT = Date.now()
      this._cancelViewportAnimation()
    },
    _handleTrackMove (data) {
      var self = this
      var contentTrackT = this._contentTrackT
      this._contentTrackT = Date.now()
      var length = this.items.length
      var other = length - this.displayMultipleItemsNumber
      function calc (val) {
        return 0.5 - 0.25 / (val + 0.5)
      }

      function move (oldVal, newVal) {
        var val = self._contentTrackViewport + oldVal
        self._contentTrackSpeed = 0.6 * self._contentTrackSpeed + 0.4 * newVal
        if (!self.circularEnabled) {
          if (val < 0 || val > other) {
            if (val < 0) {
              val = -calc(-val)
            } else {
              if (val > other) {
                val = other + calc(val - other)
              }
            }
            self._contentTrackSpeed = 0
          }
        }
        self._updateViewport(val)
      }
      var time = (this._contentTrackT - contentTrackT) || 1
      if (this.vertical) {
        move(-data.dy / this.$refs.slideFrame.offsetHeight, -data.ddy / time)
      } else {
        move(-data.dx / this.$refs.slideFrame.offsetWidth, -data.ddx / time)
      }
    },
    _handleTrackEnd (isCancel) {
      this.userTracking = false
      var t = this._contentTrackSpeed / Math.abs(this._contentTrackSpeed)
      var n = 0
      if (!isCancel && Math.abs(this._contentTrackSpeed) > 0.2) {
        n = 0.5 * t
      }
      var current = this._normalizeCurrentValue(this._viewportPosition + n)
      if (isCancel) {
        this._updateViewport(this._contentTrackViewport)
      } else {
        this.currentChangeSource = 'touch'
        this.currentSync = current
        this._animateViewport(current, 'touch', n !== 0 ? n : current === 0 && (this.circularEnabled && this._viewportPosition >= 1) ? 1 : 0)
      }
    },
    _handleContentTrack (e) {
      if (this.disableTouch || !this.items.length) {
        return
      }
      if (!this._invalid) {
        if (e.detail.state === 'start') {
          this.userTracking = true
          this._userDirectionChecked = false
          return this._handleTrackStart()
        }
        // fixed by xxxxxx
        if (e.detail.state === 'end') {
          return this._handleTrackEnd(false)
        }
        if (e.detail.state === 'cancel') {
          return this._handleTrackEnd(true)
        }
        if (this.userTracking) {
          if (!this._userDirectionChecked) {
            this._userDirectionChecked = true
            var t = Math.abs(e.detail.dx)
            var n = Math.abs(e.detail.dy)
            if (t >= n && this.vertical) {
              this.userTracking = false
            } else {
              if (t <= n && !this.vertical) {
                this.userTracking = false
              }
            }
            if (!this.userTracking) {
              if (this.autoplay) {
                this._scheduleAutoplay()
              }
              return
            }
          }
          this._handleTrackMove(e.detail)
          return false
        }
      }
    },
    /**
     * navigation
     */
    _onSwiperDotClick (index) {
      this._animateViewport(
        (this.currentSync = index),
        (this.currentChangeSource = 'click'),
        this.circularEnabled ? 1 : 0
      )
    },
    _navigationClick (type) {
      const swiperItemLength = this.items.length
      let _current = this.currentSync

      switch (type) {
        case 'prev':
          _current--
          if (_current < 0 && this.circularEnabled) {
            _current = swiperItemLength - 1
          }
          break
        case 'next':
          _current++
          if (_current >= swiperItemLength && this.circularEnabled) {
            _current = 0
          }
          break
      }

      this._onSwiperDotClick(_current)
    },
    _navigationMouseMove (e) {
      const { clientX, clientY } = e
      const {
        left,
        right,
        top,
        bottom,
        width,
        height
      } = this.$refs.slidesWrapper.getBoundingClientRect()

      if (this.vertical) {
        this.hideNavigation = !(
          clientY - top < height / 3 || bottom - clientY < height / 3
        )
      } else {
        this.hideNavigation = !(
          clientX - left < width / 3 || right - clientX < width / 3
        )
      }
    },
    _navigationMouseOut () {
      this.hideNavigation = true
    },
    _navigationSwiperAddMouseEvent () {
      if (__PLATFORM__ === 'h5') {
        const rootRef = this.$refs.slidesWrapper
        if (rootRef) {
          rootRef.removeEventListener('mousemove', this._navigationMouseMove)
          rootRef.removeEventListener('mouseout', this._navigationMouseOut)

          if (this.isNavigationAuto) {
            rootRef.addEventListener('mousemove', this._navigationMouseMove)
            rootRef.addEventListener('mouseout', this._navigationMouseOut)
          }
        }
      }
    },
    _navigationHover (event, type) {
      const target = event.currentTarget
      if (!target) return
      target.style.backgroundColor =
        type === 'over' ? this.navigationActiveColor : ''
    },
    _setNavigationState () {
      const swiperItemLength = this.items.length
      const notCircular = !this.circularEnabled

      this.prevDisabled = this.currentSync === 0 && notCircular
      this.nextDisabled =
        (this.currentSync === swiperItemLength - 1 && notCircular) ||
        (notCircular &&
          this.currentSync + this.displayMultipleItemsNumber >= swiperItemLength)
    }
  },
  render (createElement) {
    var slidesDots = []
    var swiperItems = []
    if (this.$slots.default) {
      deepClone(this.$slots.default, createElement).forEach(vnode => {
        if (vnode.componentOptions && vnode.componentOptions.tag === 'v-uni-swiper-item') {
          swiperItems.push(vnode)
        }
      })
    }
    for (let index = 0, length = swiperItems.length; index < length; index++) {
      const currentSync = this.currentSync
      slidesDots.push(createElement('div', {
        on: {
          click: () => this._onSwiperDotClick(index)
        },
        class: {
          'uni-swiper-dot': true,
          'uni-swiper-dot-active': (index < currentSync + this.displayMultipleItemsNumber && index >= currentSync) || (index < currentSync + this.displayMultipleItemsNumber - length)
        },
        style: {
          background: index === currentSync ? this.indicatorActiveColor : this.indicatorColor
        }
      }))
    }
    this.items = swiperItems
    var slidesWrapperChild = [createElement('div', {
      ref: 'slides',
      style: this.slidesStyle,
      class: 'uni-swiper-slides'
    }, [
      createElement('div', {
        ref: 'slideFrame',
        class: 'uni-swiper-slide-frame',
        style: this.slideFrameStyle
      }, swiperItems)
    ])]
    if (this.indicatorDots) {
      slidesWrapperChild.push(createElement('div', {
        ref: 'slidesDots',
        class: ['uni-swiper-dots', this.vertical ? 'uni-swiper-dots-vertical' : 'uni-swiper-dots-horizontal']
      }, slidesDots))
    }

    if (__PLATFORM__ === 'h5') {
      if (this.navigation) {
        const navigationClass = {
          'uni-swiper-navigation-hide': this.hideNavigation,
          'uni-swiper-navigation-vertical': this.vertical
        }

        const iconElement = createElement(
          'i',
          {
            domProps: {
              innerHTML: ''
            },
            class: 'uni-btn-icon',
            style: { color: this.navigationColor, fontSize: '26px' }
          }
        )

        const navigationEvent = {
          mouseover: event => this._navigationHover(event, 'over'),
          mouseout: event => this._navigationHover(event, 'out')
        }

        slidesWrapperChild.push(
          createElement(
            'div',
            {
              on: {
                click: () => this._navigationClick('prev'),
                ...navigationEvent
              },
              class: [
                'uni-swiper-navigation',
                'uni-swiper-navigation-prev',
                {
                  'uni-swiper-navigation-disabled': this.prevDisabled,
                  ...navigationClass
                }
              ]
            },
            [iconElement]
          ),
          createElement(
            'div',
            {
              on: {
                click: () => this._navigationClick('next'),
                ...navigationEvent
              },
              class: [
                'uni-swiper-navigation',
                'uni-swiper-navigation-next',
                {
                  'uni-swiper-navigation-disabled': this.nextDisabled,
                  ...navigationClass
                }
              ]
            },
            [iconElement]
          )
        )
      }
    }

    return createElement(
      'uni-swiper', {
        on: this.$listeners
      }, [createElement('div', {
        ref: 'slidesWrapper',
        class: 'uni-swiper-wrapper'
      }, slidesWrapperChild)]
    )
  }
}
</script>
<style>
uni-swiper {
  display: block;
  height: 150px;
}

uni-swiper[hidden] {
  display: none;
}

uni-swiper .uni-swiper-wrapper {
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 100%;
  -webkit-transform: translateZ(0);
  transform: translateZ(0);
}

uni-swiper .uni-swiper-slides {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

uni-swiper .uni-swiper-slide-frame {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  will-change: transform;
}

uni-swiper .uni-swiper-dots {
  position: absolute;
  font-size: 0;
}

uni-swiper .uni-swiper-dots-horizontal {
  left: 50%;
  bottom: 10px;
  text-align: center;
  white-space: nowrap;
  -webkit-transform: translate(-50%, 0);
  transform: translate(-50%, 0);
}

uni-swiper .uni-swiper-dots-horizontal .uni-swiper-dot {
  margin-right: 8px;
}

uni-swiper .uni-swiper-dots-horizontal .uni-swiper-dot:last-child {
  margin-right: 0;
}

uni-swiper .uni-swiper-dots-vertical {
  right: 10px;
  top: 50%;
  text-align: right;
  -webkit-transform: translate(0, -50%);
  transform: translate(0, -50%);
}

uni-swiper .uni-swiper-dots-vertical .uni-swiper-dot {
  display: block;
  margin-bottom: 9px;
}

uni-swiper .uni-swiper-dots-vertical .uni-swiper-dot:last-child {
  margin-bottom: 0;
}

uni-swiper .uni-swiper-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  cursor: pointer;
  transition-property: background-color;
  transition-timing-function: ease;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 50%;
}

uni-swiper .uni-swiper-dot-active {
  background-color: #000000;
}

uni-swiper .uni-swiper-navigation {
  width: 26px;
  height: 26px;
  cursor: pointer;
  position: absolute;
  top: 50%;
  margin-top: -13px;
  display: flex;
  align-items: center;
  transition: all 0.2s;
  border-radius: 50%;
  opacity: 1;
}

uni-swiper .uni-swiper-navigation-disabled {
  opacity: 0.35;
  cursor: auto;
  pointer-events: none;
}

uni-swiper .uni-swiper-navigation-hide {
  opacity: 0;
  cursor: auto;
  pointer-events: none;
}

uni-swiper .uni-swiper-navigation-prev {
  left: 10px;
}

uni-swiper .uni-swiper-navigation-prev i {
  margin-left: -1px;
  left: 10px;
}

uni-swiper .uni-swiper-navigation-prev.uni-swiper-navigation-vertical {
  top: 18px;
  left: 50%;
  margin-left: -13px;
}

uni-swiper .uni-swiper-navigation-prev.uni-swiper-navigation-vertical i {
  transform: rotate(90deg);
  margin-left: auto;
  margin-top: -2px;
}

uni-swiper .uni-swiper-navigation-next {
  right: 10px;
}

uni-swiper .uni-swiper-navigation-next i {
  transform: rotate(180deg);
}

uni-swiper .uni-swiper-navigation-next.uni-swiper-navigation-vertical {
  top: auto;
  bottom: 5px;
  left: 50%;
  margin-left: -13px;
}

uni-swiper .uni-swiper-navigation-next.uni-swiper-navigation-vertical i {
  margin-top: 2px;
  transform: rotate(270deg);
}
</style>


update

update

<template>
    <doc-guide
        :page="page"
        :hasPadding="true"
    >

对比

现在市面上的UI库非常多，当你选择时一定会有点不知所措。所以我们将主流的UI库都列在了下面，并且整理了一份全面的对比，供你参考。

希望对你的挑选有所帮助。

                    组
                    项
                    HMP UI
                    ATUI
                    Element UI
                    Ant Design
                    Morning UI

                    信息
                    介绍
                    HMP平台的组件库。
                    A revolutionary workflow to optimise your design and development.
                    一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库。
                    一套企业级的 UI 设计语言和 React 实现。
                    一套桌面Web端的UI库，基于Vue.js。

                    官网
                    -

                        https://aliqin.github.io/atui/

                        http://element.eleme.io/

                        https://ant.design/

                        https://morning-ui.com/

                    GitHub
                    -

                        https://github.com/aliqin/atui

                        https://github.com/ElemeFE/element

                        https://github.com/ant-design/ant-design/

                        https://github.com/Morning-UI/morning-ui

                    Stars on GitHub
                    -
                    ~600
                    ~25k
                    ~27k
                    ~15

                    License
                    Private
Project
                    MIT License
                    MIT License
                    MIT License
                    MIT License

                    总览
                    设计语言

                        

                        

                        

原则

                        

价值观、
原则、视觉、
模式

                        

                    技术栈

-

Vue

Vue
React
Angular

React

Vue

                    组件数量

{{hmpuiNum}}

{{atuiNum}}

{{eleNum}}

{{antdNum}}

{{morningNum}}

                    库大小

JS: -

CSS: -

JS: 303kb

CSS: 118kb

JS: 523kb

CSS: 118kb

JS: 1060kb

CSS: 303kb

JS: 349kb

CSS: 224kb

                    内置字体

                        

                        

                        

                        

                        

                    内置图标

                        

无

                        

25个

                        

70个

                        

271个

                        

无

                    常用布局

                        

无

                        

栅格、模板

                        

栅格

                        

栅格、模板、设计规则

                        

无

                    组件
                    标题

                        

                        

                        

                        

                        

                    中心内容

                        

                        

                        

                        

                        

                    标记的文本

                        

                        

                        

                        

                        

                    删除的文本

                        

                        

                        

                        

                        

                    带下划线的文本

                        

                        

                        

                        

                        

                    小号文本

                        

                        

                        

                        

                        

                    着重文本

                        

                        

                        

                        

                        

                    斜体文本

                        

                        

                        

                        

                        

                    左/居中/右对齐文本

                        

                        

                        

                        

                        

                    大/小/首字大写文本

                        

                        

                        

                        

                        

                    引用

                        

                        

                        

                        

                        

                    有序列表

                        

                        

                        

                        

                        

                    无序列表

                        

                        

                        

                        

                        

                    内联列表

                        

                        

                        

                        

                        

                    描述列表

                        

                        

                        

                        

                        

                    项目列表

                        

                        

                        

                        

                        

                    文本颜色

                        

                        

                        

                        

                        

                    醒目文本

                        

                        

                        

                        

                        

                    栅格

                        

                        

                        

                        

                        

                    卡片

                        

                        

                        

                        

                        

                    容器

                        

                        

                        

                        

                        

                    区块

                        

                        

                        

                        

                        

                    分频器

                        

                        

                        

                        

                        

                    居中容器

                        

                        

                        

                        

                        

                    页头

                        

                        

                        

                        

                        

                    徽章

                        

                        

                        

                        

                        

                    标签

                        

                        

                        

                        

                        

                    统计

                        

                        

                        

                        

                        

                    行动栏

                        

                        

                        

                        

                        

                    表单组

                        

                        

                        

                        

                        

                    按钮组

                        

                        

                        

                        

                        

                    巨幕

                        

                        

                        

                        

                        

                    文章

                        

                        

                        

                        

                        

                    导航菜单

                        

                        

                        

                        

                        

                    图片

                        

                        

                        

                        

                        

                    警告

                        

                        

                        

                        

                        

                    时间轴

                        

                        

                        

                        

                        

                    按钮

                        

                        

                        

                        

                        

                    链接(文字按钮)

                        

                        

                        

                        

                        

                    下拉式按钮组(下拉菜单)

                        

                        

                        

                        

                        

                    标签页

                        

                        

                        

                        

                        

                    表格

                        

                        

                        

                        

                        

                    分页

                        

                        

                        

                        

                        

                    模拟盒(对话框)

                        

                        

                        

                        

                        

                    日历

                        

                        

                        

                        

                        

                    加载

                        

                        

                        

                        

                        

                    面包屑

                        

                        

                        

                        

                        

                    小提示(文字提示)

                        

                        

                        

                        

                        

                    消息

                        

                        

                        

                        

                        

                    轮播

                        

                        

                        

                        

                        

                    自动完成(搜索条)

                        

                        

                        

                        

                        

                    树形控件

                        

                        

                        

                        

                        

                    折叠面板(手风琴)

                        

                        

                        

                        

                        

                    弹出框(气泡卡片)

                        

                        

                        

                        

                        

                    滚动跟随

                        

                        

                        

                        

                        

                    步骤条

                        

                        

                        

                        

                        

                    进度条

                        

                        

                        

                        

                        

                    气泡确认框(弹框)

                        

                        

                        

                        

                        

                    通知

                        

                        

                        

                        

                        

                    锚点

                        

                        

                        

                        

                        

                    回到顶部

                        

                        

                        

                        

                        

                    音频

                        

                        

                        

                        

                        

                    视频

                        

                        

                        

                        

                        

                    多级联动

                        

                        

                        

                        

                        

                    文本输入

                        

                        

                        

                        

                        

                    段落输入

                        

                        

                        

                        

                        

                    开关

                        

                        

                        

                        

                        

                    下拉选择

                        

                        

                        

                        

                        

                    复选框组

                        

                        

                        

                        

                        

                    单选框组

                        

                        

                        

                        

                        

                    多项输入

                        

                        

                        

                        

                        

                    多项表单输入

                        

                        

                        

                        

                        

                    时间选择

                        

                        

                        

                        

                        

                    日期选择

                        

                        

                        

                        

                        

                    日期时间选择

                        

                        

                        

                        

                        

                    上传

                        

                        

                        

                        

                        

                    图片热区输入

                        

                        

                        

                        

                        

                    级联选择器

                        

                        

                        

                        

                        

                    滑块输入器

                        

                        

                        

                        

                        

                    计数器

                        

                        

                        

                        

                        

                    评分

                        

                        

                        

                        

                        

                    颜色选择器

                        

                        

                        

                        

                        

                    穿梭框

                        

                        

                        

                        

                        

                    提及

                        

                        

                        

                        

                        

                    树形选择器

                        

                        

                        

                        

                        

                    富文本输入框

                        

                        

                        

                        

                        

    </doc-guide>
</template>

<template>
    <doc-guide
        :page="page"
        :hasPadding="true"
    >

对比

现在市面上的UI库非常多，当你选择时一定会有点不知所措。所以我们将主流的UI库都列在了下面，并且整理了一份全面的对比，供你参考。

希望对你的挑选有所帮助。

                    组
                    项
                    HMP UI
                    ATUI
                    Element UI
                    Ant Design
                    Morning UI

                    基本
信息
                    介绍
                    HMP平台的组件库。
                    A revolutionary workflow to optimise your design and development.
                    一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库。
                    一套企业级的 UI 设计语言和 React 实现。
                    一套桌面Web端的UI库，基于Vue.js。

                    官网
                    -

                        https://aliqin.github.io/atui/

                        http://element.eleme.io/

                        https://ant.design/

                        https://morning-ui.com/

                    GitHub
                    -

                        https://github.com/aliqin/atui

                        https://github.com/ElemeFE/element

                        https://github.com/ant-design/ant-design/

                        https://github.com/Morning-UI/morning-ui

                    Stars on GitHub
                    -
                    ~600
                    ~25k
                    ~27k
                    ~15

                    License
                    Private
Project
                    MIT License
                    MIT License
                    MIT License
                    MIT License

                    基础
                    设计语言

                        

                        

                        

原则

                        

价值观、
原则、视觉、
模式

                        

                    技术栈

-

Vue

Vue
React
Angular

React

Vue

                    组件数量

{{hmpuiNum}}

{{atuiNum}}

{{eleNum}}

{{antdNum}}

{{morningNum}}

                    库大小

JS: -

CSS: -

JS: 303kb

CSS: 118kb

JS: 523kb

CSS: 118kb

JS: 1060kb

CSS: 303kb

JS: 349kb

CSS: 224kb

                    内置字体

                        

                        

                        

                        

                        

                    内置图标

                        

无

                        

25个

                        

70个

                        

271个

                        

无

                    常用布局

                        

无

                        

栅格、模板

                        

栅格

                        

栅格、模板、设计规则

                        

无

                    组件
                    标题

                        

                        

                        

                        

                        

                    中心内容

                        

                        

                        

                        

                        

                    标记的文本

                        

                        

                        

                        

                        

                    删除的文本

                        

                        

                        

                        

                        

                    带下划线的文本

                        

                        

                        

                        

                        

                    小号文本

                        

                        

                        

                        

                        

                    着重文本

                        

                        

                        

                        

                        

                    斜体文本

                        

                        

                        

                        

                        

                    左/居中/右对齐文本

                        

                        

                        

                        

                        

                    大/小/首字大写文本

                        

                        

                        

                        

                        

                    引用

                        

                        

                        

                        

                        

                    有序列表

                        

                        

                        

                        

                        

                    无序列表

                        

                        

                        

                        

                        

                    内联列表

                        

                        

                        

                        

                        

                    描述列表

                        

                        

                        

                        

                        

                    项目列表

                        

                        

                        

                        

                        

                    文本颜色

                        

                        

                        

                        

                        

                    醒目文本

                        

                        

                        

                        

                        

                    栅格

                        

                        

                        

                        

                        

                    卡片

                        

                        

                        

                        

                        

                    容器

                        

                        

                        

                        

                        

                    区块

                        

                        

                        

                        

                        

                    分频器

                        

                        

                        

                        

                        

                    居中容器

                        

                        

                        

                        

                        

                    页头

                        

                        

                        

                        

                        

                    徽章

                        

                        

                        

                        

                        

                    标签

                        

                        

                        

                        

                        

                    统计

                        

                        

                        

                        

                        

                    行动栏

                        

                        

                        

                        

                        

                    表单组

                        

                        

                        

                        

                        

                    按钮组

                        

                        

                        

                        

                        

                    巨幕

                        

                        

                        

                        

                        

                    文章

                        

                        

                        

                        

                        

                    导航菜单

                        

                        

                        

                        

                        

                    图片

                        

                        

                        

                        

                        

                    警告

                        

                        

                        

                        

                        

                    时间轴

                        

                        

                        

                        

                        

                    按钮

                        

                        

                        

                        

                        

                    链接(文字按钮)

                        

                        

                        

                        

                        

                    下拉式按钮组(下拉菜单)

                        

                        

                        

                        

                        

                    标签页

                        

                        

                        

                        

                        

                    表格

                        

                        

                        

                        

                        

                    分页

                        

                        

                        

                        

                        

                    模拟盒(对话框)

                        

                        

                        

                        

                        

                    日历

                        

                        

                        

                        

                        

                    加载

                        

                        

                        

                        

                        

                    面包屑

                        

                        

                        

                        

                        

                    小提示(文字提示)

                        

                        

                        

                        

                        

                    消息

                        

                        

                        

                        

                        

                    轮播

                        

                        

                        

                        

                        

                    自动完成(搜索条)

                        

                        

                        

                        

                        

                    树形控件

                        

                        

                        

                        

                        

                    折叠面板(手风琴)

                        

                        

                        

                        

                        

                    弹出框(气泡卡片)

                        

                        

                        

                        

                        

                    滚动跟随

                        

                        

                        

                        

                        

                    步骤条

                        

                        

                        

                        

                        

                    进度条

                        

                        

                        

                        

                        

                    气泡确认框(弹框)

                        

                        

                        

                        

                        

                    通知

                        

                        

                        

                        

                        

                    锚点

                        

                        

                        

                        

                        

                    回到顶部

                        

                        

                        

                        

                        

                    音频

                        

                        

                        

                        

                        

                    视频

                        

                        

                        

                        

                        

                    多级联动

                        

                        

                        

                        

                        

                    文本输入

                        

                        

                        

                        

                        

                    段落输入

                        

                        

                        

                        

                        

                    开关

                        

                        

                        

                        

                        

                    下拉选择

                        

                        

                        

                        

                        

                    复选框组

                        

                        

                        

                        

                        

                    单选框组

                        

                        

                        

                        

                        

                    多项输入

                        

                        

                        

                        

                        

                    多项表单输入

                        

                        

                        

                        

                        

                    时间选择

                        

                        

                        

                        

                        

                    日期选择

                        

                        

                        

                        

                        

                    日期时间选择

                        

                        

                        

                        

                        

                    上传

                        

                        

                        

                        

                        

                    图片热区输入

                        

                        

                        

                        

                        

                    级联选择器

                        

                        

                        

                        

                        

                    滑块输入器

                        

                        

                        

                        

                        

                    计数器

                        

                        

                        

                        

                        

                    评分

                        

                        

                        

                        

                        

                    颜色选择器

                        

                        

                        

                        

                        

                    穿梭框

                        

                        

                        

                        

                        

                    提及

                        

                        

                        

                        

                        

                    树形选择器

                        

                        

                        

                        

                        

                    富文本输入框

                        

                        

                        

                        

                        

    </doc-guide>
</template>


Matrix bot change test message to say "check the channel"

<script lang="coffee">
import EventBus from '@/shared/services/event_bus'
import AppConfig from '@/shared/services/app_config'
import Records from '@/shared/services/records'
import Flash  from '@/shared/services/flash'

export default
  props:
    chatbot: Object

  data: ->
    kinds: AppConfig.webhookEventKinds
    testing: false

  methods:
    submit: ->
      @chatbot.save()
      .then =>
        Flash.success 'chatbot.saved'
        @close()
      .catch (b) =>
        console.log @chatbot.errors

    testConnection: ->
      @testing = true
      Records.remote.post('chatbots/test',
        server: @chatbot.server
        access_token: @chatbot.accessToken
        channel: @chatbot.channel
        group_name: "group name was here"
      ).finally =>
        Flash.success('chatbot.check_for_test_message')
        @testing = false

</script>
<template lang="pug">
v-card.chatbot-matrix-form
  v-card-title
    h1.headline(tabindex="-1" v-t="'chatbot.chatbot'")
    v-spacer
    dismiss-modal-button
  v-card-text
    v-text-field(:label="$t('chatbot.name')" v-model="chatbot.name" hint="The name of your chatroom")
    v-text-field(:label="$t('chatbot.homeserver_url')"  v-model="chatbot.server" hint="https://example.com")
    v-text-field(
      :label="$t('chatbot.access_token')"
      v-model="chatbot.accessToken"
      placeholder="Looks like: syt_cm9ZXJ0Lmd1dGiaWNG9vbWWv_QsMCFvOcUxucxajF_1Ty2"
      hint="Login as the bot user, then find: User menu > All settings > Help & about > Access token")
    v-text-field(
      :label="$t('chatbot.channel')"
      v-model="chatbot.channel"
      placeholder="E.g. #general:example.com or !hZAAvLtRpxPTHIvfLC:example.com"
      hint="As bot user: Room options > Settings > Advanced > Internal room ID")
    //- v-checkbox.webhook-form__include-body(v-model="chatbot.includeBody" :label="$t('webhook.include_body_label')" hide-details)
    //- p.mt-4.text--secondary(v-t="'webhook.event_kind_helptext'")
    //- v-checkbox.webhook-form__event-kind(hide-details v-for='kind in kinds' v-model='chatbot.eventKinds' :key="kind" :label="$t('webhook.event_kinds.' + kind)" :value="kind")

    v-card-actions
      v-spacer
      v-btn(@click='testConnection' v-t="'chatbot.test_connection'" :loading="testing")
      v-btn(color='primary' @click='submit' v-t="'common.action.save'")
</template>

<script lang="coffee">
import EventBus from '@/shared/services/event_bus'
import AppConfig from '@/shared/services/app_config'
import Records from '@/shared/services/records'
import Flash  from '@/shared/services/flash'

export default
  props:
    chatbot: Object

  data: ->
    kinds: AppConfig.webhookEventKinds
    testing: false

  methods:
    submit: ->
      @chatbot.save()
      .then =>
        Flash.success 'chatbot.saved'
        @close()
      .catch (b) =>
        console.log @chatbot.errors

    testConnection: ->
      @testing = true
      Records.remote.post('chatbots/test',
        server: @chatbot.server
        access_token: @chatbot.accessToken
        channel: @chatbot.channel
        group_name: "group name was here"
      ).then =>
        Flash.success('chatbot.test_connection_ok')
      , =>
        Flash.error('chatbot.test_connection_bad')
      .finally =>
        @testing = false

</script>
<template lang="pug">
v-card.chatbot-matrix-form
  v-card-title
    h1.headline(tabindex="-1" v-t="'chatbot.chatbot'")
    v-spacer
    dismiss-modal-button
  v-card-text
    v-text-field(:label="$t('chatbot.name')" v-model="chatbot.name" hint="The name of your chatroom")
    v-text-field(:label="$t('chatbot.homeserver_url')"  v-model="chatbot.server" hint="https://example.com")
    v-text-field(
      :label="$t('chatbot.access_token')"
      v-model="chatbot.accessToken"
      placeholder="Looks like: syt_cm9ZXJ0Lmd1dGiaWNG9vbWWv_QsMCFvOcUxucxajF_1Ty2"
      hint="Login as the bot user, then find: User menu > All settings > Help & about > Access token")
    v-text-field(
      :label="$t('chatbot.channel')"
      v-model="chatbot.channel"
      placeholder="E.g. #general:example.com or !hZAAvLtRpxPTHIvfLC:example.com"
      hint="As bot user: Room options > Settings > Advanced > Internal room ID")
    //- v-checkbox.webhook-form__include-body(v-model="chatbot.includeBody" :label="$t('webhook.include_body_label')" hide-details)
    //- p.mt-4.text--secondary(v-t="'webhook.event_kind_helptext'")
    //- v-checkbox.webhook-form__event-kind(hide-details v-for='kind in kinds' v-model='chatbot.eventKinds' :key="kind" :label="$t('webhook.event_kinds.' + kind)" :value="kind")

    v-card-actions
      v-spacer
      v-btn(@click='testConnection' v-t="'chatbot.test_connection'" :loading="testing")
      v-btn(color='primary' @click='submit' v-t="'common.action.save'")
</template>


Bug fixed

Bug fixed

<script>
import bindEvents from '../base/bindEvent.js'
import {createPoint} from '../base/factory.js'

export default {
  name: 'map-overlay-polyline',
  render (h) {
    return
  },
  props: {
    points: {
      type: Array
    },
    strokeColor: {
      type: String
    },
    strokeWeight: {
      type: Number
    },
    strokeOpacity: {
      type: Number
    },
    strokeStype: {
      type: String
    },
    massClear: {
      type: Boolean,
      default: true
    },
    clicking: {
      type: Boolean,
      default: true
    },
    editing: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    points: {
      handler (val, oldVal) {
        this.reloadOverlay()
      },
      deep: true
    },
    strokeColor (val) {
      this.overlay.getStrokeColor(val)
    },
    strokeColor (val) {
      this.overlay.getStrokeOpacity(val)
    },
    strokeWeight (val) {
      this.overlay.getStrokeOpacity(val)
    },
    editing (val) {
      val ? this.overlay.enableEditing() : this.overlay.disableEditing()
    },
    massClear (val) {
      val ? this.overlay.enableMassClear() : this.overlay.disableMassClear()
    },
    clicking (val) {
      this.reloadOverlay()
    }
  },
  methods: {
    addOverlay () {
      const {points, strokeColor, strokeWeight, strokeOpacity, strokeStyle, editing, massClear, clicking} = this
      const {BMap, map} = this.$parent
      const overlay = new BMap.Polyline(points.map(item => createPoint(BMap, {lng: item.lng, lat: item.lat})), {
        strokeColor,
        strokeWeight,
        strokeOpacity,
        strokeStyle,
        enableEditing: editing,
        enableMassClear: massClear,
        enableClicking: clicking
      })
      console.log(points)
      this.overlay = overlay
      map.addOverlay(overlay)
      bindEvents.call(this, overlay)
    },
    removeOverlay () {
      const {BMap, map} = this.$parent
      map.removeOverlay(this.overlay)
    },
    reloadOverlay () {
      this.$nextTick(() => {
        this.removeOverlay()
        this.addOverlay()
      })
    }
  },
  mounted () {
    const {BMap, map} = this.$parent
    this.$parent.$on('ready', () => {
      this.addOverlay()
    })
  }
}
</script>

<script>
import bindEvents from '../base/bindEvent.js'
import {createPoint} from '../base/factory.js'

export default {
  name: 'map-overlay-polyline',
  render (h) {
    return
  },
  props: {
    points: {
      type: Array
    },
    strokeColor: {
      type: String
    },
    strokeWeight: {
      type: Number
    },
    strokeOpacity: {
      type: Number
    },
    strokeStype: {
      type: String
    },
    massClear: {
      type: Boolean,
      default: true
    },
    clicking: {
      type: Boolean,
      default: true
    },
    editing: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    points: {
      handler (val, oldVal) {
        this.reloadOverlay()
      },
      deep: true
    },
    strokeColor (val) {
      this.overlay.getStrokeColor(val)
    },
    strokeColor (val) {
      this.overlay.getStrokeOpacity(val)
    },
    strokeWeight (val) {
      this.overlay.getStrokeOpacity(val)
    },
    editing (val) {
      val ? this.overlay.enableEditing() : this.overlay.disableEditing()
    },
    massClear (val) {
      val ? this.overlay.enableMassClear() : this.overlay.disableMassClear()
    }
  },
  methods: {
    addOverlay () {
      const {points, strokeColor, strokeWeight, strokeOpacity, strokeStyle, editing, massClear, clicking} = this
      const {BMap, map} = this.$parent
      const overlay = new BMap.Polyline(points.map(item => createPoint(BMap, {lng: item.lng, lat: item.lat})), {
        strokeColor,
        strokeWeight,
        strokeOpacity,
        strokeStyle,
        enableEditing: editing,
        enableMassClear: massClear,
        enableClicking: clicking
      })
      console.log(points)
      this.overlay = overlay
      map.addOverlay(overlay)
      bindEvents.call(this, overlay)
    },
    removeOverlay () {
      const {BMap, map} = this.$parent
      map.removeOverlay(this.overlay)
    },
    reloadOverlay () {
      this.$nextTick(() => {
        this.removeOverlay()
        this.addOverlay()
      })
    }
  },
  mounted () {
    const {BMap, map} = this.$parent
    this.$parent.$on('ready', () => {
      this.addOverlay()
    })
  }
}
</script>


Only show search bar if logged in

Only show search bar if logged in

<template>
  <v-app id="keep">
    <v-app-bar
      app
      clipped-left
      color="amber"
    >
      <v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>

        Wolk
        Notes

      <v-text-field
        solo-inverted
        flat
        hide-details
        label="Search"
        prepend-inner-icon="mdi-magnify"
        v-model="searchTerm"
        v-debounce:200ms="searchTermChanged"
        v-if="isSignedIn"
      ></v-text-field>

    </v-app-bar>

    <v-navigation-drawer
      v-model="drawer"
      app
      clipped
      color="grey lighten-4"
    >
      <NotebookBar></NotebookBar>
    </v-navigation-drawer>

    <v-content>
      <v-container
        fluid
        class="lighten-4"
      >
        <router-view></router-view>
      </v-container>
    </v-content>
    <ToastMessages></ToastMessages>
  </v-app>
</template>

<template>
  <v-app id="keep">
    <v-app-bar
      app
      clipped-left
      color="amber"
    >
      <v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>

        Wolk
        Notes

      <v-text-field
        solo-inverted
        flat
        hide-details
        label="Search"
        prepend-inner-icon="mdi-magnify"
        v-model="searchTerm"
        v-debounce:200ms="searchTermChanged"
      ></v-text-field>

    </v-app-bar>

    <v-navigation-drawer
      v-model="drawer"
      app
      clipped
      color="grey lighten-4"
    >
      <NotebookBar></NotebookBar>
    </v-navigation-drawer>

    <v-content>
      <v-container
        fluid
        class="lighten-4"
      >
        <router-view></router-view>
      </v-container>
    </v-content>
    <ToastMessages></ToastMessages>
  </v-app>
</template>