diff --git a/react/features/filmstrip/actionTypes.js b/react/features/filmstrip/actionTypes.js index bd70e3e18..9bbc166c7 100644 --- a/react/features/filmstrip/actionTypes.js +++ b/react/features/filmstrip/actionTypes.js @@ -1,5 +1,16 @@ /** - * The type of action sets the visibility of the entire filmstrip; + * The type of the action which sets whether or not the filmstrip is being + * hovered with the cursor. + * + * { + * type: SET_FILMSTRIP_HOVERED, + * hovered: boolean + * } + */ +export const SET_FILMSTRIP_HOVERED = Symbol('SET_FILMSTRIP_HOVERED'); + +/** + * The type of action sets the visibility of the entire filmstrip. * * { * type: SET_FILMSTRIP_VISIBILITY, diff --git a/react/features/filmstrip/actions.js b/react/features/filmstrip/actions.js index 9e1f297b4..ce4d88e68 100644 --- a/react/features/filmstrip/actions.js +++ b/react/features/filmstrip/actions.js @@ -1,7 +1,25 @@ import { + SET_FILMSTRIP_HOVERED, SET_FILMSTRIP_VISIBILITY } from './actionTypes'; +/** + * Sets if the filmstrip is currently being hovered over. + * + * @param {boolean} hovered - Whether or not the filmstrip is currently being + * hovered over. + * @returns {{ + * type: SET_FILMSTRIP_HOVERED, + * hovered: boolean + * }} + */ +export function setFilmstripHovered(hovered) { + return { + type: SET_FILMSTRIP_HOVERED, + hovered + }; +} + /** * Sets if the entire filmstrip should be visible. * diff --git a/react/features/filmstrip/components/Filmstrip.web.js b/react/features/filmstrip/components/Filmstrip.web.js index a7c54ce28..d701b646e 100644 --- a/react/features/filmstrip/components/Filmstrip.web.js +++ b/react/features/filmstrip/components/Filmstrip.web.js @@ -1,10 +1,12 @@ /* @flow */ +import _ from 'lodash'; import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Toolbox } from '../../toolbox'; +import { setFilmstripHovered } from '../actions'; import { shouldRemoteVideosBeVisible } from '../functions'; /** @@ -14,19 +16,68 @@ import { shouldRemoteVideosBeVisible } from '../functions'; * @extends Component */ class Filmstrip extends Component { + _isHovered: boolean; + + _notifyOfHoveredStateUpdate: Function; + + _onMouseOut: Function; + + _onMouseOver: Function; + + /** + * {@code Filmstrip} component's property types. + * + * @static + */ static propTypes = { + /** + * Whether or not remote videos are currently being hovered over. + */ + _hovered: React.PropTypes.bool, + /** * Whether or not the remote videos should be visible. Will toggle * a class for hiding the videos. */ _remoteVideosVisible: React.PropTypes.bool, + /** + * Updates the redux store with filmstrip hover changes. + */ + dispatch: React.PropTypes.func, + /** * Whether or not the toolbox should be displayed within the filmstrip. */ displayToolbox: React.PropTypes.bool }; + /** + * Initializes a new {@code Filmstrip} instance. + * + * @param {Object} props - The read-only properties with which the new + * instance is to be initialized. + */ + constructor(props) { + super(props); + + // Debounce the method for dispatching the new filmstrip handled state + // so that it does not get called with each mouse movement event. This + // also works around an issue where mouseout and then a mouseover event + // is fired when hovering over remote thumbnails, which are not yet in + // react. + this._notifyOfHoveredStateUpdate + = _.debounce(this._notifyOfHoveredStateUpdate, 100); + + // Cache the current hovered state for _updateHoveredState to always + // send the last known hovered state. + this._isHovered = false; + + // Bind event handlers so they are only bound once for every instance. + this._onMouseOver = this._onMouseOver.bind(this); + this._onMouseOut = this._onMouseOut.bind(this); + } + /** * Implements React's {@link Component#render()}. * @@ -54,7 +105,9 @@ class Filmstrip extends Component { id = 'remoteVideos'>
+ id = 'filmstripLocalVideo' + onMouseOut = { this._onMouseOut } + onMouseOver = { this._onMouseOver } />