feat(indicators): move the "top toolbar" indicators to react (#1699)
* feat(indicators): move the "top toolbar" indicators to react * wrap baseindicator
This commit is contained in:
parent
fcda36a8e0
commit
0481e4cf00
|
@ -58,7 +58,6 @@
|
|||
padding: $toolbarPadding;
|
||||
padding-bottom: 0;
|
||||
|
||||
.connection-indicator-container,
|
||||
.connection-indicator,
|
||||
span.indicator {
|
||||
margin-right: em(5, 8);
|
||||
|
@ -302,7 +301,7 @@
|
|||
margin: 0px 0px 0px 5px;
|
||||
}
|
||||
|
||||
#raisehandindicator {
|
||||
.raisehandindicator {
|
||||
background: $raiseHandBg;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,71 +446,16 @@ const IndicatorFontSizes = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets an "indicator" span for a video thumbnail.
|
||||
* If element doesn't exist then creates it and appends
|
||||
* video span container.
|
||||
*
|
||||
* @param {object} opts
|
||||
* @param opts.indicatorId {String} - identificator of indicator
|
||||
* @param opts.videoSpanId {String} - identificator of video span
|
||||
* @param opts.content {String} HTML content of indicator
|
||||
* @param opts.tooltip {String} - tooltip key for translation
|
||||
*
|
||||
* @returns {HTMLSpanElement} indicatorSpan
|
||||
*/
|
||||
getVideoThumbnailIndicatorSpan(opts = {}) {
|
||||
let indicatorId = opts.indicatorId;
|
||||
let videoSpanId = opts.videoSpanId;
|
||||
let indicators = $(`#${videoSpanId} [id="${indicatorId}"]`);
|
||||
let indicatorSpan;
|
||||
|
||||
if (indicators.length <= 0) {
|
||||
indicatorSpan = document.createElement('span');
|
||||
|
||||
indicatorSpan.className = 'indicator';
|
||||
indicatorSpan.id = indicatorId;
|
||||
|
||||
if(opts.content) {
|
||||
indicatorSpan.innerHTML = opts.content;
|
||||
}
|
||||
|
||||
if (opts.tooltip) {
|
||||
this.setTooltip(indicatorSpan, opts.tooltip, "top");
|
||||
APP.translation.translateElement($(indicatorSpan));
|
||||
}
|
||||
|
||||
this._resizeIndicator(indicatorSpan);
|
||||
|
||||
document.getElementById(videoSpanId)
|
||||
.querySelector('.videocontainer__toptoolbar')
|
||||
.appendChild(indicatorSpan);
|
||||
} else {
|
||||
indicatorSpan = indicators[0];
|
||||
}
|
||||
|
||||
return indicatorSpan;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizing indicator element passing via argument
|
||||
* according to the current thumbnail size
|
||||
* @param {HTMLElement} indicator - indicator element
|
||||
* @private
|
||||
*/
|
||||
_resizeIndicator(indicator) {
|
||||
let height = $('#localVideoContainer').height();
|
||||
let fontSize = this.getIndicatorFontSize(height);
|
||||
$(indicator).css('font-size', fontSize);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns font size for indicators according to current
|
||||
* height of thumbnail
|
||||
* @param {Number} - height - current height of thumbnail
|
||||
* @param {Number} [thumbnailHeight] - current height of thumbnail
|
||||
* @returns {Number} - font size for current height
|
||||
*/
|
||||
getIndicatorFontSize(height) {
|
||||
getIndicatorFontSize(thumbnailHeight) {
|
||||
const height = typeof thumbnailHeight === 'undefined'
|
||||
? $('#localVideoContainer').height() : thumbnailHeight;
|
||||
|
||||
const { SMALL, MEDIUM } = ThumbnailSizes;
|
||||
let fontSize = IndicatorFontSizes.NORMAL;
|
||||
|
||||
|
|
|
@ -529,6 +529,8 @@ RemoteVideo.prototype.remove = function () {
|
|||
|
||||
this.removeAvatar();
|
||||
|
||||
this._unmountIndicators();
|
||||
|
||||
// Make sure that the large video is updated if are removing its
|
||||
// corresponding small video.
|
||||
this.VideoLayout.updateAfterThumbRemoved(this.id);
|
||||
|
@ -688,10 +690,6 @@ RemoteVideo.createContainer = function (spanId) {
|
|||
indicatorBar.className = "videocontainer__toptoolbar";
|
||||
container.appendChild(indicatorBar);
|
||||
|
||||
const connectionIndicatorContainer = document.createElement('span');
|
||||
connectionIndicatorContainer.className = 'connection-indicator-container';
|
||||
indicatorBar.appendChild(connectionIndicatorContainer);
|
||||
|
||||
let toolbar = document.createElement('div');
|
||||
toolbar.className = "videocontainer__toolbar";
|
||||
container.appendChild(toolbar);
|
||||
|
|
|
@ -18,7 +18,9 @@ import {
|
|||
import { DisplayName } from '../../../react/features/display-name';
|
||||
import {
|
||||
AudioMutedIndicator,
|
||||
DominantSpeakerIndicator,
|
||||
ModeratorIndicator,
|
||||
RaisedHandIndicator,
|
||||
VideoMutedIndicator
|
||||
} from '../../../react/features/filmstrip';
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
@ -99,6 +101,30 @@ function SmallVideo(VideoLayout) {
|
|||
*/
|
||||
this._popoverIsHovered = false;
|
||||
|
||||
/**
|
||||
* Whether or not the connection indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showConnectionIndicator = true;
|
||||
|
||||
/**
|
||||
* Whether or not the dominant speaker indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showDominantSpeaker = false;
|
||||
|
||||
/**
|
||||
* Whether or not the raised hand indicator should be displayed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._showRaisedHand = false;
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onPopoverHover = this._onPopoverHover.bind(this);
|
||||
this.updateView = this.updateView.bind(this);
|
||||
|
@ -252,12 +278,9 @@ SmallVideo.prototype.updateConnectionStats = function (percent, object) {
|
|||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype.removeConnectionIndicator = function () {
|
||||
const connectionIndicatorContainer
|
||||
= this.container.querySelector('.connection-indicator-container');
|
||||
this._showConnectionIndicator = false;
|
||||
|
||||
if (connectionIndicatorContainer) {
|
||||
ReactDOM.unmountComponentAtNode(connectionIndicatorContainer);
|
||||
}
|
||||
this.updateIndicators();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -643,17 +666,9 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
|||
return;
|
||||
}
|
||||
|
||||
let indicatorSpanId = "dominantspeakerindicator";
|
||||
let content = `<i id="indicatoricon"
|
||||
class="indicatoricon fa fa-bullhorn"></i>`;
|
||||
let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({
|
||||
videoSpanId: this.videoSpanId,
|
||||
indicatorId: indicatorSpanId,
|
||||
content,
|
||||
tooltip: 'speaker'
|
||||
});
|
||||
this._showDominantSpeaker = show;
|
||||
|
||||
UIUtil.setVisible(indicatorSpan, show);
|
||||
this.updateIndicators();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -667,17 +682,9 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
|
|||
return;
|
||||
}
|
||||
|
||||
let indicatorSpanId = "raisehandindicator";
|
||||
let content = `<i id="indicatoricon"
|
||||
class="icon-raised-hand indicatoricon"></i>`;
|
||||
let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({
|
||||
indicatorId: indicatorSpanId,
|
||||
videoSpanId: this.videoSpanId,
|
||||
content,
|
||||
tooltip: 'raisedHand'
|
||||
});
|
||||
this._showRaisedHand = show;
|
||||
|
||||
UIUtil.setVisible(indicatorSpan, show);
|
||||
this.updateIndicators();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -746,21 +753,60 @@ SmallVideo.prototype.updateConnectionIndicator = function (newStats = {}) {
|
|||
this._cachedConnectionStats
|
||||
= Object.assign({}, this._cachedConnectionStats, newStats);
|
||||
|
||||
const connectionIndicatorContainer
|
||||
= this.container.querySelector('.connection-indicator-container');
|
||||
this.updateIndicators();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the React element responsible for showing connection status, dominant
|
||||
* speaker, and raised hand icons. Uses instance variables to get the necessary
|
||||
* state to display. Will create the React element if not already created.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype.updateIndicators = function () {
|
||||
const indicatorToolbar
|
||||
= this.container.querySelector('.videocontainer__toptoolbar');
|
||||
|
||||
const iconSize = UIUtil.getIndicatorFontSize();
|
||||
|
||||
/* jshint ignore:start */
|
||||
ReactDOM.render(
|
||||
<ConnectionIndicator
|
||||
isLocalVideo = { this.isLocal }
|
||||
onHover = { this._onPopoverHover }
|
||||
showMoreLink = { this.isLocal }
|
||||
stats = { this._cachedConnectionStats } />,
|
||||
connectionIndicatorContainer
|
||||
<div>
|
||||
{ this._showConnectionIndicator
|
||||
? <ConnectionIndicator
|
||||
iconSize = { iconSize }
|
||||
isLocalVideo = { this.isLocal }
|
||||
onHover = { this._onPopoverHover }
|
||||
showMoreLink = { this.isLocal }
|
||||
stats = { this._cachedConnectionStats } />
|
||||
: null }
|
||||
{ this._showRaisedHand
|
||||
? <RaisedHandIndicator iconSize = { iconSize } /> : null }
|
||||
{ this._showDominantSpeaker
|
||||
? <DominantSpeakerIndicator iconSize = { iconSize } /> : null }
|
||||
</div>,
|
||||
indicatorToolbar
|
||||
);
|
||||
/* jshint ignore:end */
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the React element responsible for showing connection status, dominant
|
||||
* speaker, and raised hand icons.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype._unmountIndicators = function () {
|
||||
const indicatorToolbar
|
||||
= this.container.querySelector('.videocontainer__toptoolbar');
|
||||
|
||||
if (indicatorToolbar) {
|
||||
ReactDOM.unmountComponentAtNode(indicatorToolbar);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the current state of the connection indicator popover being hovered.
|
||||
* If hovered, display the small video as if it is hovered.
|
||||
|
|
|
@ -44,11 +44,7 @@ export default class Filmstrip extends Component {
|
|||
id = 'localAudio'
|
||||
muted = { true } />
|
||||
<div className = 'videocontainer__toolbar' />
|
||||
<div className = 'videocontainer__toptoolbar'>
|
||||
<span
|
||||
className
|
||||
= 'connection-indicator-container' />
|
||||
</div>
|
||||
<div className = 'videocontainer__toptoolbar' />
|
||||
<div className = 'videocontainer__hoverOverlay' />
|
||||
<div className = 'displayNameContainer' />
|
||||
<div className = 'avatar-container' />
|
||||
|
|
|
@ -1,23 +1,26 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import BaseIndicator from './BaseIndicator';
|
||||
|
||||
/**
|
||||
* React {@code Component} for showing an audio muted icon with a tooltip.
|
||||
*
|
||||
* @extends BaseIndicator
|
||||
* @extends Component
|
||||
*/
|
||||
class AudioMutedIndicator extends BaseIndicator {
|
||||
class AudioMutedIndicator extends Component {
|
||||
/**
|
||||
* Initializes a new AudioMutedIcon instance.
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @param {Object} props - The read-only React Component props with which
|
||||
* the new instance is to be initialized.
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._classNames = 'audioMuted toolbar-icon';
|
||||
this._iconClass = 'icon-mic-disabled';
|
||||
this._tooltipKey = 'videothumbnail.mute';
|
||||
render() {
|
||||
return (
|
||||
<BaseIndicator
|
||||
className = 'audioMuted toolbar-icon'
|
||||
iconClassName = 'icon-mic-disabled'
|
||||
tooltipKey = 'videothumbnail.mute' />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,41 @@ import UIUtil from '../../../../../modules/UI/util/UIUtil';
|
|||
* @extends Component
|
||||
*/
|
||||
class BaseIndicator extends Component {
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
iconClassName: '',
|
||||
iconSize: 'auto',
|
||||
id: ''
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
/**
|
||||
* The CSS class names to set on the root element of the component.
|
||||
*/
|
||||
className: React.PropTypes.string,
|
||||
|
||||
/**
|
||||
* The CSS classnames to set on the icon element of the component.
|
||||
*/
|
||||
iconClassName: React.PropTypes.string,
|
||||
|
||||
/**
|
||||
* The front size for the icon.
|
||||
*/
|
||||
iconSize: React.PropTypes.string,
|
||||
|
||||
/**
|
||||
* The ID attribue to set on the root element of the component.
|
||||
*/
|
||||
id: React.PropTypes.string,
|
||||
|
||||
/**
|
||||
* The translation key to use for displaying a tooltip when hovering
|
||||
* over the component.
|
||||
*/
|
||||
tooltipKey: React.PropTypes.string
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code BaseIndicator} instance.
|
||||
*
|
||||
|
@ -17,20 +52,6 @@ class BaseIndicator extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
* The CSS classes to apply to the root HTML element of the component.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this._classNames = '';
|
||||
|
||||
/**
|
||||
* The CSS class which will display an icon.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this._iconClass = '';
|
||||
|
||||
/**
|
||||
* An internal reference to the HTML element at the top of the
|
||||
* component's DOM hierarchy. The reference is needed for attaching a
|
||||
|
@ -40,13 +61,6 @@ class BaseIndicator extends Component {
|
|||
*/
|
||||
this._rootElement = null;
|
||||
|
||||
/**
|
||||
* The translation key for the text to display in the tooltip.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this._tooltipKey = '';
|
||||
|
||||
// Bind event handler so it is only bound once for every instance.
|
||||
this._setRootElementRef = this._setRootElementRef.bind(this);
|
||||
}
|
||||
|
@ -69,10 +83,13 @@ class BaseIndicator extends Component {
|
|||
*/
|
||||
render() {
|
||||
return (
|
||||
<span className = { this._classNames }>
|
||||
<span
|
||||
className = { this.props.className }
|
||||
id = { this.props.id }
|
||||
ref = { this._setRootElementRef }>
|
||||
<i
|
||||
className = { this._iconClass }
|
||||
ref = { this._setRootElementRef } />
|
||||
className = { this.props.iconClassName }
|
||||
style = {{ fontSize: this.props.iconSize }} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
@ -101,7 +118,7 @@ class BaseIndicator extends Component {
|
|||
// becomes available for tooltips.
|
||||
UIUtil.setTooltip(
|
||||
this._rootElement,
|
||||
this._tooltipKey,
|
||||
this.props.tooltipKey,
|
||||
'top'
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import BaseIndicator from './BaseIndicator';
|
||||
|
||||
/**
|
||||
* Thumbnail badge showing that the participant is the dominant speaker in
|
||||
* the conference.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class DominantSpeakerIndicator extends Component {
|
||||
/**
|
||||
* {@code DominantSpeakerIndicator} component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The font-size for the icon.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
iconSize: React.PropTypes.number
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<BaseIndicator
|
||||
className = 'indicator show-inline'
|
||||
iconClassName = 'indicatoricon fa fa-bullhorn'
|
||||
iconSize = { `${this.props.iconSize}px` }
|
||||
id = 'dominantspeakerindicator'
|
||||
tooltipKey = 'speaker' />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DominantSpeakerIndicator;
|
|
@ -1,23 +1,26 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import BaseIndicator from './BaseIndicator';
|
||||
|
||||
/**
|
||||
* React {@code Component} for showing a moderator icon with a tooltip.
|
||||
*
|
||||
* @extends BaseIndicator
|
||||
* @extends Component
|
||||
*/
|
||||
class ModeratorIndicator extends BaseIndicator {
|
||||
class ModeratorIndicator extends Component {
|
||||
/**
|
||||
* Initializes a new ModeratorIndicator instance.
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @param {Object} props - The read-only React Component props with which
|
||||
* the new instance is to be initialized.
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._classNames = 'focusindicator toolbar-icon right';
|
||||
this._iconClass = 'icon-star';
|
||||
this._tooltipKey = 'videothumbnail.moderator';
|
||||
render() {
|
||||
return (
|
||||
<BaseIndicator
|
||||
className = 'focusindicator toolbar-icon right'
|
||||
iconClassName = 'icon-star'
|
||||
tooltipKey = 'videothumbnail.moderator' />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import BaseIndicator from './BaseIndicator';
|
||||
|
||||
/**
|
||||
* Thumbnail badge showing that the participant would like to speak.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class RaisedHandIndicator extends Component {
|
||||
/**
|
||||
* {@code RaisedHandIndicator} component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The font-size for the icon.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
iconSize: React.PropTypes.number
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
render() {
|
||||
return (
|
||||
<BaseIndicator
|
||||
className = 'raisehandindicator indicator show-inline'
|
||||
iconClassName = 'icon-raised-hand indicatoricon'
|
||||
iconSize = { `${this.props.iconSize}px` }
|
||||
tooltipKey = 'raisedHand' />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RaisedHandIndicator;
|
|
@ -1,23 +1,24 @@
|
|||
import React, { Component } from 'react';
|
||||
import BaseIndicator from './BaseIndicator';
|
||||
|
||||
/**
|
||||
* React {@code Component} for showing a video muted icon with a tooltip.
|
||||
*
|
||||
* @extends BaseIndicator
|
||||
* @extends Component
|
||||
*/
|
||||
class VideoMutedIndicator extends BaseIndicator {
|
||||
class VideoMutedIndicator extends Component {
|
||||
/**
|
||||
* Initializes a new VideoMutedIndicator instance.
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @param {Object} props - The read-only React Component props with which
|
||||
* the new instance is to be initialized.
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._classNames = 'videoMuted toolbar-icon';
|
||||
this._iconClass = 'icon-camera-disabled';
|
||||
this._tooltipKey = 'videothumbnail.videomute';
|
||||
render() {
|
||||
return (
|
||||
<BaseIndicator
|
||||
className = 'videoMuted toolbar-icon'
|
||||
iconClassName = 'icon-camera-disabled'
|
||||
tooltipKey = 'videothumbnail.videomute' />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
export { default as AudioMutedIndicator } from './AudioMutedIndicator';
|
||||
export { default as DominantSpeakerIndicator }
|
||||
from './DominantSpeakerIndicator';
|
||||
export { default as ModeratorIndicator } from './ModeratorIndicator';
|
||||
export { default as RaisedHandIndicator } from './RaisedHandIndicator';
|
||||
export { default as VideoMutedIndicator } from './VideoMutedIndicator';
|
||||
|
|
Loading…
Reference in New Issue