import classNames from 'classnames'
import PropTypes from '../../../_util/vue-types'
import addEventListener from '../../../_util/Dom/addEventListener'
import warning from '../../../_util/warning'
import { initDefaultProps } from '../../../_util/props-util'
import Steps from './Steps'
import Marks from './Marks'
import Handle from '../Handle'
import * as utils from '../utils'
function noop () {}
export default function createSlider (Component) {
// const displayName = `ComponentEnhancer(${Component.displayName})`
const propTypes = {
...Component.propTypes,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
marks: PropTypes.object,
included: PropTypes.bool,
prefixCls: PropTypes.string,
disabled: PropTypes.bool,
handle: PropTypes.func,
dots: PropTypes.bool,
vertical: PropTypes.bool,
minimumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
maximumTrackStyle: PropTypes.object, // just for compatibility, will be deperecate
handleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
trackStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
railStyle: PropTypes.object,
dotStyle: PropTypes.object,
activeDotStyle: PropTypes.object,
autoFocus: PropTypes.bool,
}
return {
name: 'createSlider',
mixins: [Component],
props: initDefaultProps(propTypes, {
...Component.defaultProps,
prefixCls: 'rc-slider',
min: 0,
max: 100,
step: 1,
marks: {},
handle (h, { index, refStr, className, style, ...restProps }) {
delete restProps.dragging
const handleProps = {
props: {
...restProps,
},
attrs: {
refStr,
},
class: className,
style,
key: index,
}
return
},
included: true,
disabled: false,
dots: false,
vertical: false,
trackStyle: [{}],
handleStyle: [{}],
railStyle: {},
dotStyle: {},
activeDotStyle: {},
}),
model: {
prop: 'value',
event: 'change',
},
data () {
if (process.env.NODE_ENV !== 'production') {
const { step, max, min } = this
warning(
step && Math.floor(step) === step ? (max - min) % step === 0 : true,
'Slider[max] - Slider[min] (%s) should be a multiple of Slider[step] (%s)',
max - min,
step
)
}
this.handlesRefs = []
return {}
},
beforeDestroy () {
this.$nextTick(() => {
// if (super.componentWillUnmount) super.componentWillUnmount()
this.removeDocumentEvents()
})
},
mounted () {
this.$nextTick(() => {
// Snapshot testing cannot handle refs, so be sure to null-check this.
this.document = this.$refs.sliderRef && this.$refs.sliderRef.ownerDocument
this.setHandleRefs()
})
},
methods: {
setHandleRefs () {
const refs = this.$refs.handleRef
const children = Array.prototype.slice.call(refs.children)
children.map((item) => {
const refStr = item.getAttribute('refStr')
if (refStr.indexOf('handleRef') > -1) {
const handleArr = refStr.split('handleRef')
this.handlesRefs[handleArr[1]] = item
}
})
},
onMouseDown (e) {
if (e.button !== 0) { return }
const isVertical = this.vertical
let position = utils.getMousePosition(isVertical, e)
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
this.dragOffset = 0
} else {
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
this.dragOffset = position - handlePosition
position = handlePosition
}
this.removeDocumentEvents()
this.onStart(position)
this.addDocumentMouseEvents()
},
onTouchStart (e) {
if (utils.isNotTouchEvent(e)) return
const isVertical = this.vertical
let position = utils.getTouchPosition(isVertical, e)
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
this.dragOffset = 0
} else {
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target)
this.dragOffset = position - handlePosition
position = handlePosition
}
this.onStart(position)
this.addDocumentTouchEvents()
utils.pauseEvent(e)
},
onFocus (e) {
const { vertical } = this
if (utils.isEventFromHandle(e, this.handlesRefs)) {
const handlePosition = utils.getHandleCenterPosition(vertical, e.target)
this.dragOffset = 0
this.onStart(handlePosition)
utils.pauseEvent(e)
this.$emit('focus', e)
}
},
onBlur (e) {
console.dir(e)
this.onEnd(e)
this.$emit('blur', e)
},
addDocumentTouchEvents () {
// just work for Chrome iOS Safari and Android Browser
this.onTouchMoveListener = addEventListener(this.document, 'touchmove', this.onTouchMove)
this.onTouchUpListener = addEventListener(this.document, 'touchend', this.onEnd)
},
addDocumentMouseEvents () {
this.onMouseMoveListener = addEventListener(this.document, 'mousemove', this.onMouseMove)
this.onMouseUpListener = addEventListener(this.document, 'mouseup', this.onEnd)
},
removeDocumentEvents () {
/* eslint-disable no-unused-expressions */
this.onTouchMoveListener && this.onTouchMoveListener.remove()
this.onTouchUpListener && this.onTouchUpListener.remove()
this.onMouseMoveListener && this.onMouseMoveListener.remove()
this.onMouseUpListener && this.onMouseUpListener.remove()
/* eslint-enable no-unused-expressions */
},
onMouseUp () {
if (this.$children && this.$children[this.prevMovedHandleIndex]) {
const handleCom = utils.getComponentProps(this.$children[this.prevMovedHandleIndex], 'clickFocus')
if (handleCom) {
handleCom.clickFocus()
}
}
},
onMouseMove (e) {
if (!this.$refs.sliderRef) {
this.onEnd()
return
}
const position = utils.getMousePosition(this.vertical, e)
this.onMove(e, position - this.dragOffset)
},
onTouchMove (e) {
if (utils.isNotTouchEvent(e) || !this.$refs.sliderRef) {
this.onEnd()
return
}
const position = utils.getTouchPosition(this.vertical, e)
this.onMove(e, position - this.dragOffset)
},
onKeyDown (e) {
if (this.$refs.sliderRef && utils.isEventFromHandle(e, this.handlesRefs)) {
this.onKeyboard(e)
}
},
focus () {
if (!this.disabled) {
this.handlesRefs[0].focus()
}
},
blur () {
if (!this.disabled) {
this.handlesRefs[0].blur()
}
},
getSliderStart () {
const slider = this.$refs.sliderRef
const rect = slider.getBoundingClientRect()
return this.vertical ? rect.top : rect.left
},
getSliderLength () {
const slider = this.$refs.sliderRef
if (!slider) {
return 0
}
const coords = slider.getBoundingClientRect()
return this.vertical ? coords.height : coords.width
},
calcValue (offset) {
const { vertical, min, max } = this
const ratio = Math.abs(Math.max(offset, 0) / this.getSliderLength())
const value = vertical ? (1 - ratio) * (max - min) + min : ratio * (max - min) + min
return value
},
calcValueByPos (position) {
const pixelOffset = position - this.getSliderStart()
const nextValue = this.trimAlignValue(this.calcValue(pixelOffset))
return nextValue
},
calcOffset (value) {
const { min, max } = this
const ratio = (value - min) / (max - min)
return ratio * 100
},
onClickMarkLabel (e, value) {
e.stopPropagation()
this.$emit('change', { value })
},
},
render (h) {
const {
prefixCls,
marks,
dots,
step,
included,
disabled,
vertical,
min,
max,
maximumTrackStyle,
railStyle,
dotStyle,
activeDotStyle,
} = this
const { tracks, handles } = this.renderSlider(h)
const sliderClassName = classNames(prefixCls, {
[`${prefixCls}-with-marks`]: Object.keys(marks).length,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-vertical`]: vertical,
})
const markProps = {
props: {
vertical,
marks,
included,
lowerBound: this.getLowerBound(),
upperBound: this.getUpperBound(),
max,
min,
className: `${prefixCls}-mark`,
},
on: {
clickLabel: disabled ? noop : this.onClickMarkLabel,
},
}
return (
{tracks}
{handles}
{this.$slots.default}
)
},
}
}