codingblocks/qit.cloud

View on GitHub
website/src/components/Player/Slider.js

Summary

Maintainability
B
5 hrs
Test Coverage
import React from 'react'
 
import styled from 'styled-components'
 
const ScrubberWrapper = styled.div`
position: relative;
display: block;
`
 
const ScrubberHandle = styled.g`
visibility: ${props => (props.scrubbing ? 'visible' : 'hidden')};
`
 
const Scrubber = styled.svg`
${props =>
props.scrubbing
? `
cursor: -webkit-grabbing;
cursor: grabbing;
`
: `
cursor: grab;
`}
 
position: absolute;
top: -8px;
left: 0
 
&:hover ${ScrubberHandle} {
visibility: visible
}
`
 
const ScrubberLabel = styled.svg`
position: absolute;
top: -40px;
left: 0;
visibility: ${props => (props.scrubbing ? 'visible' : 'hidden')};
`
 
export default class Slider extends React.Component {
constructor (props) {
super(props)
this.state = {
scrubbing: false,
scrubPosition: 0,
containerWidth: 0,
leftEdge: 0
}
this.sliderRef = React.createRef()
}
 
componentDidMount () {
this.resizeSlider()
window.addEventListener('resize', this.resizeSlider)
}
 
componentWillUnmount () {
window.removeEventListener('resize', this.resizeSlider)
}
 
resizeSlider = () => {
this.setState({
containerWidth: this.sliderRef.current.offsetWidth,
leftEdge: this.sliderRef.current.getBoundingClientRect().left
})
}
 
getScrubberValue = () => {
let value =
(this.getScrubberPosition() / this.state.containerWidth) * this.props.max
if (value < 0) {
return 0
}
if (value > this.props.max) {
return this.props.max
}
return value
}
 
formatScrubberValue = value => {
if (this.props.formatter) {
return this.props.formatter(value)
}
return value
}
 
getScrubberPosition = () => {
if (this.state.scrubbing) {
return this.state.scrubPosition
}
if (this.props.max) {
return (this.state.containerWidth * this.props.value) / this.props.max
}
return 0
}
 
getEventHorizontalPosition = event => {
if (typeof event.clientX === 'number') {
return event.clientX - this.state.leftEdge
}
if (event.targetTouches.length) {
return event.targetTouches[0].clientX - this.state.leftEdge
}
if (event.changedTouches.length) {
return event.changedTouches[0].clientX - this.state.leftEdge
}
if (event.touches.length) {
return event.touches[0].clientX - this.state.leftEdge
}
Avoid too many `return` statements within this function.
return 0
}
 
onGrabScrubber = initialEvent => {
initialEvent.preventDefault()
 
this.setState({
scrubbing: true,
scrubPosition: this.getEventHorizontalPosition(initialEvent)
})
 
if (initialEvent.type === 'mousedown') {
this.addMouseListeners()
} else if (initialEvent.type === 'touchstart') {
this.addTouchListeners()
}
}
 
onScrub = event => {
event.preventDefault()
this.setState({ scrubPosition: this.getEventHorizontalPosition(event) })
}
 
onScrubDisrupted = event => {
event.preventDefault()
this.setState({ scrubbing: false })
this.removeListeners()
}
 
onScrubEnd = event => {
event.preventDefault()
this.setState({ scrubbing: false })
 
let newPosition = this.getEventHorizontalPosition(event)
 
if (newPosition <= this.state.containerWidth && newPosition >= 0) {
this.props.onValueChanged(
(this.props.max * newPosition) / this.state.containerWidth
)
}
 
this.removeListeners()
}
 
addTouchListeners = () => {
window.addEventListener('touchmove', this.onScrub, { passive: false })
window.addEventListener('touchend', this.onScrubEnd, { passive: false })
window.addEventListener('touchcancel', this.onScrubDisrupted)
}
 
addMouseListeners = () => {
window.addEventListener('mousemove', this.onScrub, { passive: false })
window.addEventListener('mouseup', this.onScrubEnd, { passive: false })
}
 
removeListeners = () => {
window.removeEventListener('mousemove', this.onScrub)
window.removeEventListener('mouseup', this.onScrubEnd)
window.removeEventListener('touchmove', this.onScrub)
window.removeEventListener('touchend', this.onScrubEnd)
window.removeEventListener('touchcancel', this.onScrubDisrupted)
}
 
Function `render` has 90 lines of code (exceeds 25 allowed). Consider refactoring.
render () {
return (
<div ref={this.sliderRef}>
<ScrubberWrapper>
{!this.props.hideLabel ? (
<ScrubberLabel
xmlns='http://www.w3.org/2000/svg'
viewBox={`0 0 70 40`}
width={70}
height={40}
scrubbing={this.state.scrubbing}
style={{
transform: `translateX(${
this.getScrubberPosition() > this.state.containerWidth - 35
? this.state.containerWidth - 70
: Math.max(0, this.getScrubberPosition() - 35)
}px)`
}}
>
<polygon
points='0,0 0,30 30,30 35,36 40,30 70,30 70,0'
fill='#359189'
stroke='#ffffff'
/>
<text fill='white' y='50%' x='50%' textAnchor='middle'>
{this.formatScrubberValue(this.getScrubberValue())}
</text>
</ScrubberLabel>
) : null}
<Scrubber
scrubbing={this.state.scrubbing}
xmlns='http://www.w3.org/2000/svg'
width={this.state.containerWidth}
height={20}
viewBox={`0 0 ${this.state.containerWidth} 20`}
>
<defs>
<radialGradient className='gradient'>
<stop offset='0%' stopColor='#a756f5' />
<stop offset='100%' stopColor='#6f04d4' />
</radialGradient>
</defs>
<g
onMouseDown={this.onGrabScrubber}
onTouchStart={this.onGrabScrubber}
>
Similar blocks of code found in 2 locations. Consider refactoring.
<rect
x={0}
y={0}
width={this.state.containerWidth}
height={20}
opacity='0'
/>
Similar blocks of code found in 2 locations. Consider refactoring.
<rect
x={0}
y={8}
width={this.state.containerWidth}
height={4}
fill='#E0E0E0'
/>
<rect
x={0}
y={8}
height={4}
fill='#a756f5'
width={`${
this.getScrubberPosition() >= 0
? this.getScrubberPosition()
: 0
}`}
/>
</g>
<ScrubberHandle
onMouseDown={this.onGrabScrubber}
onTouchStart={this.onGrabScrubber}
scrubbing={this.state.scrubbing}
>
<circle
cx={0}
cy={10}
r={7}
style={{
transform: `translate(${this.getScrubberPosition()}px)`,
fill: 'url(.gradient)'
}}
/>
</ScrubberHandle>
</Scrubber>
</ScrubberWrapper>
</div>
)
}
}