diff --git a/js/webui/src/elements.js b/js/webui/src/elements.js index 429fb017..5ae0de59 100644 --- a/js/webui/src/elements.js +++ b/js/webui/src/elements.js @@ -2,6 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import spriteSvg from 'open-iconic/sprite/sprite.svg' import { makeClassName } from './dom_utils.js'; +import { bindHandlers } from './utils.js'; function makeClickHandler(callback) { @@ -69,6 +70,99 @@ Button.propTypes = { active: PropTypes.bool }; +const repeatInterval = 500; + +function isLeftButtonOrTouch(e) +{ + return e.button === 0 || typeof e.touches !== 'undefined'; +} + +export class RepeatingButton extends React.PureComponent +{ + constructor(props) + { + super(props); + this.intervalId = null; + this.hasInitialClick = false; + bindHandlers(this); + } + + handleTimer() + { + this.hasInitialClick = true; + this.props.onClick(); + } + + handleClick(e) + { + if (e.button !== 0) + return; + + e.preventDefault(); + + if (!this.hasInitialClick) + this.props.onClick(); + } + + componentDidUpdate(prevProps, prevState, snapshot) + { + if (prevProps.onClick === this.props.onClick || !this.intervalId) + return; + + clearInterval(this.intervalId); + this.intervalId = setInterval(this.handleTimer, repeatInterval); + } + + handleStart(e) + { + if (!isLeftButtonOrTouch(e) || this.intervalId) + return; + + this.hasInitialClick = false; + this.intervalId = setInterval(this.handleTimer, repeatInterval); + } + + handleEnd(e) + { + if (!isLeftButtonOrTouch(e) || !this.intervalId) + return; + + clearInterval(this.intervalId); + this.intervalId = null; + } + + render() + { + const { name, title, className, active } = this.props; + + const fullClassName = 'button' + + (className ? ' ' + className : '') + + (active ? ' active' : ''); + + return ( + + + + ); + } +} + +RepeatingButton.propTypes = { + name: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + className: PropTypes.string, + onClick: PropTypes.func.isRequired, + active: PropTypes.bool +}; + export function Menu(props) { const { children } = props; diff --git a/js/webui/src/volume_control.js b/js/webui/src/volume_control.js index 72cd1173..1096bb18 100644 --- a/js/webui/src/volume_control.js +++ b/js/webui/src/volume_control.js @@ -1,6 +1,6 @@ import React from 'react' import PropTypes from 'prop-types' -import { Button } from './elements.js' +import { Button, RepeatingButton } from './elements.js'; import { bindHandlers, dbToLinear, linearToDb } from './utils.js' import ModelBinding from './model_binding.js'; import { DropdownButton } from './dropdown.js'; @@ -54,7 +54,7 @@ class VolumeControl_ extends React.PureComponent this.context.playerModel.volumeUp(); } - handleVolumeDown(e) + handleVolumeDown() { this.context.playerModel.volumeDown(); } @@ -84,8 +84,8 @@ class VolumeControl_ extends React.PureComponent { isUpDown ? <> -