Merge pull request #1071 from jitsi/ongoing-work-video-thumbnails

Ongoing work video thumbnails
This commit is contained in:
Paweł Domas 2016-10-27 17:13:27 -05:00 committed by GitHub
commit 2fe69d409b
14 changed files with 375 additions and 255 deletions

View File

@ -1279,10 +1279,6 @@ export default {
APP.UI.updateRecordingState(status);
});
room.on(ConferenceEvents.USER_STATUS_CHANGED, function (id, status) {
APP.UI.updateUserStatus(id, status);
});
room.on(ConferenceEvents.KICKED, () => {
APP.UI.hideStats();
APP.UI.notifyKicked();

View File

@ -50,6 +50,15 @@
border-radius: 50%;
}
/**
* Absolute position the element at the top left corner
**/
@mixin topLeft() {
position: absolute;
top: 0;
left: 0;
}
@mixin absoluteAligning($sizeX, $sizeY) {
top: 50%;
left: 50%;

View File

@ -11,10 +11,10 @@ $hangupFontSize: 2em;
$defaultToolbarSize: 50px;
// Video layout.
$thumbnailIndicatorSize: 23px;
$thumbnailToolbarHeight: 22px;
$thumbnailIndicatorBorder: 0px;
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
$thumbnailVideoMargin: 2px;
$thumbnailToolbarHeight: 25px;
/**
* Color variables.
@ -46,6 +46,7 @@ $thumbnailPictogramColor: #fff;
$dominantSpeakerBg: #165ecc;
$raiseHandBg: #D6D61E;
$audioLevelBg: #44A5FF;
$connectionIndicatorBg: #165ecc;
$audioLevelShadow: rgba(9, 36, 77, 0.9);
$videoStateIndicatorColor: $defaultColor;
$videoStateIndicatorBackground: $toolbarBackground;

View File

@ -58,17 +58,36 @@
/**
* The toolbar of the video thumbnail.
*/
.videocontainer__toolbar {
.videocontainer__toolbar,
.videocontainer__toptoolbar {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
z-index: 3;
width: 100%;
box-sizing: border-box; // Includes the padding in the 100% width.
height: $thumbnailToolbarHeight;
max-height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.videocontainer__toolbar {
bottom: 0;
padding: 0 5px 0 5px;
height: $thumbnailToolbarHeight;
}
.videocontainer__toptoolbar {
$toolbarPadding: 5px;
top: 0;
padding: $toolbarPadding;
padding-bottom: 0;
height: $thumbnailIndicatorSize + $toolbarPadding;
}
.videocontainer__hoverOverlay {
position: relative;
width: 100%;
height: 100%;
visibility: hidden;
background: rgba(0,0,0,.6);
z-index: 2;
}
#remoteVideos .videocontainer.videoContainerFocused,
@ -176,8 +195,10 @@
.videocontainer .editdisplayname {
display: inline-block;
position: absolute;
left: 30%;
width: 40%;
left: 10%;
width: 80%;
top: 50%;
@include transform(translateY(-40%));
color: $participantNameColor;
text-align: center;
text-overflow: ellipsis;
@ -200,72 +221,10 @@
padding: 0;
}
.videocontainer>span.status {
display: inline-block;
position: absolute;
color: #FFFFFF;
background: rgba(0,0,0,.7);
text-align: center;
text-overflow: ellipsis;
width: 70%;
height: 15%;
left: 15%;
bottom: 2%;
padding: 5px;
font-size: 10pt;
overflow: hidden;
white-space: nowrap;
z-index: 2;
border-radius:3px;
}
.connectionindicator
{
display: inline-block;
position: absolute;
top: 7px;
right: 0;
padding: 0px 5px;
z-index: 3;
width: 18px;
height: 13px;
}
.connection.connection_empty
{
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
.connection.connection_lost
{
color: #8B8B8B;
overflow: visible;
}
.connection.connection_full
{
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
.connection
{
position: absolute;
left: 0px;
top: 0px;
font-size: 8pt;
border: 0px;
width: 18px;
height: 13px;
}
#localVideoContainer>span.status:hover,
#localVideoContainer .displayname:hover {
cursor: text;
}
.videocontainer>span.status,
.videocontainer .displayname {
pointer-events: none;
}
@ -278,7 +237,6 @@
pointer-events: auto !important;
}
.videocontainer>a.status,
.videocontainer>a.displayname {
display: inline-block;
position: absolute;
@ -323,25 +281,92 @@
margin: 0px 0px 0px 5px;
}
.videocontainer>span.indicator {
position: absolute;
top: 0px;
left: 0px;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
z-index: 3;
text-align: center;
background: $dominantSpeakerBg;
margin: 7px;
display: inline-block;
color: $thumbnailPictogramColor;
font-size: 8pt;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
#raisehandindicator {
background: $raiseHandBg;
}
.videocontainer>#raisehandindicator {
background: $raiseHandBg;
#connectionindicator {
background: $connectionIndicatorBg;
}
.videocontainer__toptoolbar span.indicator {
position: relative;
font-size: 8pt;
text-align: center;
line-height: $thumbnailToolbarHeight;
display: none;
padding: 0;
margin-right: 5px;
float: left;
@include circle($thumbnailIndicatorSize);
box-sizing: border-box;
z-index: 3;
background: $dominantSpeakerBg;
color: $thumbnailPictogramColor;
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
.indicatoricon {
position: absolute;
top: 50%;
left: 0;
@include transform(translateY(-50%));
width: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
line-height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
}
.connection {
position: relative;
margin: 0 auto;
width: 12px;
height: 8px;
&_empty
{
@include topLeft();
max-width: 12px;
width: 12px;
color: #8B8B8B;/*#FFFFFF*/
overflow: hidden;
}
&_lost
{
@include topLeft();
max-width: 12px;
width: 12px;
color: #8B8B8B;
overflow: visible;
}
&_full
{
@include topLeft();
max-width: 12px;
width: 12px;
color: #FFFFFF;/*#15A1ED*/
overflow: hidden;
}
}
.icon-connection,
.icon-connection-lost {
font-size: 6pt;
}
}
.remotevideomenu
{
display: inline-block;
position: absolute;
top: 0px;
right: 0;
margin: 7px;
z-index: 3;
width: 18px;
height: 13px;
color: #FFF;
font-size: 8pt;
}
/**
@ -384,12 +409,6 @@
}
}
#indicatoricon {
width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder;
}
#reloadPresentation {
display: none;
position: absolute;

View File

@ -254,6 +254,8 @@
</span>
<audio id="localAudio" autoplay muted></audio>
<div class="videocontainer__toolbar"></div>
<div class="videocontainer__toptoolbar"></div>
<div class="videocontainer__hoverOverlay"></div>
</span>
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>

View File

@ -609,10 +609,6 @@ UI.removeUser = function (id, displayName) {
VideoLayout.removeParticipantContainer(id);
};
UI.updateUserStatus = function (id, status) {
VideoLayout.setPresenceStatus(id, status);
};
/**
* Update videotype for specified user.
* @param {string} id user id

View File

@ -625,7 +625,7 @@ function SharedVideoThumb (url)
this.videoSpanId = "sharedVideoContainer";
this.container = this.createContainer(this.videoSpanId);
this.container.onclick = this.videoClick.bind(this);
this.bindHoverHandler();
SmallVideo.call(this, VideoLayout);
this.isVideoMuted = true;
}

View File

@ -98,14 +98,27 @@ var JitsiPopover = (function () {
var self = this;
$(".jitsipopover").on("mouseenter", function () {
self.popoverIsHovered = true;
if(typeof self.onHoverPopover === "function") {
self.onHoverPopover(self.popoverIsHovered);
}
}).on("mouseleave", function () {
self.popoverIsHovered = false;
self.hide();
if(typeof self.onHoverPopover === "function") {
self.onHoverPopover(self.popoverIsHovered);
}
});
this.refreshPosition();
};
/**
* Adds a hover listener to the popover.
*/
JitsiPopover.prototype.addOnHoverPopover = function (listener) {
this.onHoverPopover = listener;
};
/**
* Refreshes the position of the popover.
*/

View File

@ -136,7 +136,7 @@ const TOOLTIP_POSITIONS = {
element.setAttribute('data-i18n', '[content]' + key);
APP.translation.translateElement($(element));
}
}
},
/**
@ -237,6 +237,18 @@ const TOOLTIP_POSITIONS = {
$("#"+id).addClass("hide");
},
/**
* Shows / hides the element with the given jQuery selector.
*
* @param {jQuery} selector the jQuery selector of the element to show/hide
* @param {boolean} isVisible
*/
setVisibility(selector, isVisible) {
if (selector && selector.length > 0) {
selector.css("visibility", isVisible ? "visible" : "hidden");
}
},
hideDisabledButtons: function (mappings) {
var selector = Object.keys(mappings)
.map(function (buttonName) {
@ -376,6 +388,49 @@ const TOOLTIP_POSITIONS = {
"cursor": "default"
});
}
},
/**
* 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));
}
document.getElementById(videoSpanId)
.querySelector('.videocontainer__toptoolbar')
.appendChild(indicatorSpan);
} else {
indicatorSpan = indicators[0];
}
return indicatorSpan;
}
};

View File

@ -2,13 +2,15 @@
/* jshint -W101 */
import JitsiPopover from "../util/JitsiPopover";
import VideoLayout from "./VideoLayout";
import UIUtil from "../util/UIUtil";
/**
* Constructs new connection indicator.
* @param videoContainer the video container associated with the indicator.
* @param videoId the identifier of the video
* @constructor
*/
function ConnectionIndicator(videoContainer, id) {
function ConnectionIndicator(videoContainer, videoId) {
this.videoContainer = videoContainer;
this.bandwidth = null;
this.packetLoss = null;
@ -18,7 +20,7 @@ function ConnectionIndicator(videoContainer, id) {
this.isResolutionHD = null;
this.transport = [];
this.popover = null;
this.id = id;
this.id = videoId;
this.create();
}
@ -32,12 +34,12 @@ function ConnectionIndicator(videoContainer, id) {
* 0: string}}
*/
ConnectionIndicator.connectionQualityValues = {
98: "18px", //full
81: "15px",//4 bars
64: "11px",//3 bars
47: "7px",//2 bars
30: "3px",//1 bar
0: "0px"//empty
98: "100%", //full
81: "80%",//4 bars
64: "55%",//3 bars
47: "40%",//2 bars
30: "20%",//1 bar
0: "0"//empty
};
ConnectionIndicator.getIP = function(value) {
@ -259,18 +261,22 @@ function createIcon(classes, iconClass) {
* Creates the indicator
*/
ConnectionIndicator.prototype.create = function () {
this.connectionIndicatorContainer = document.createElement("div");
this.connectionIndicatorContainer.className = "connectionindicator";
this.connectionIndicatorContainer.style.display = "none";
this.videoContainer.container.appendChild(
this.connectionIndicatorContainer);
this.popover = new JitsiPopover(
$("#" + this.videoContainer.videoSpanId + " > .connectionindicator"), {
content: "<div class=\"connection-info\" " +
"data-i18n='connectionindicator.na'></div>",
skin: "black",
onBeforePosition: el => APP.translation.translateElement(el)
});
let indicatorId = 'connectionindicator';
let element = UIUtil.getVideoThumbnailIndicatorSpan({
videoSpanId: this.videoContainer.videoSpanId,
indicatorId
});
element.classList.add('show');
this.connectionIndicatorContainer = element;
let popoverContent = (
`<div class="connection-info" data-i18n="${indicatorId}.na"></div>`
);
this.popover = new JitsiPopover($(element), {
content: popoverContent,
skin: "black",
onBeforePosition: el => APP.translation.translateElement(el)
});
// override popover show method to make sure we will update the content
// before showing the popover
@ -283,13 +289,19 @@ ConnectionIndicator.prototype.create = function () {
origShowFunc.call(this.popover);
}.bind(this);
this.emptyIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_empty"], "icon-connection"));
this.fullIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_full"], "icon-connection"));
this.interruptedIndicator = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_lost"],"icon-connection-lost"));
let connectionIconContainer = document.createElement('div');
connectionIconContainer.className = 'connection indicatoricon';
this.emptyIcon = connectionIconContainer.appendChild(
createIcon(["connection_empty"], "icon-connection"));
this.fullIcon = connectionIconContainer.appendChild(
createIcon(["connection_full"], "icon-connection"));
this.interruptedIndicator = connectionIconContainer.appendChild(
createIcon(["connection_lost"],"icon-connection-lost"));
$(this.interruptedIndicator).hide();
this.connectionIndicatorContainer.appendChild(connectionIconContainer);
};
/**
@ -320,7 +332,6 @@ ConnectionIndicator.prototype.updateConnectionStatusIndicator
$(this.interruptedIndicator).show();
$(this.emptyIcon).hide();
$(this.fullIcon).hide();
this.updateConnectionQuality(0 /* zero bars */);
}
};
@ -427,4 +438,11 @@ ConnectionIndicator.prototype.updateResolutionIndicator = function () {
}
};
/**
* Adds a hover listener to the popover.
*/
ConnectionIndicator.prototype.addPopoverHoverListener = function (listener) {
this.popover.addOnHoverPopover(listener);
};
export default ConnectionIndicator;

View File

@ -11,6 +11,8 @@ function LocalVideo(VideoLayout, emitter) {
this.videoSpanId = "localVideoContainer";
this.container = $("#localVideoContainer").get(0);
this.localVideoId = null;
this.createConnectionIndicator();
this.bindHoverHandler();
if(config.enableLocalVideoFlip)
this._buildContextMenu();
this.isLocal = true;
@ -27,7 +29,6 @@ function LocalVideo(VideoLayout, emitter) {
// Set default display name.
this.setDisplayName();
this.createConnectionIndicator();
this.addAudioLevelIndicator();
}
@ -70,7 +71,6 @@ LocalVideo.prototype.setDisplayName = function(displayName) {
nameSpan = document.createElement('span');
nameSpan.className = 'displayname';
document.getElementById(this.videoSpanId)
.querySelector('.videocontainer__toolbar')
.appendChild(nameSpan);
@ -104,7 +104,6 @@ LocalVideo.prototype.setDisplayName = function(displayName) {
APP.translation.translateElement($(editableText));
this.container
.querySelector('.videocontainer__toolbar')
.appendChild(editableText);
var self = this;
@ -115,7 +114,7 @@ LocalVideo.prototype.setDisplayName = function(displayName) {
e.preventDefault();
e.stopPropagation();
$localDisplayName.hide();
UIUtil.setVisibility($localDisplayName, false);
$editDisplayName.show();
$editDisplayName.focus();
$editDisplayName.select();
@ -123,7 +122,7 @@ LocalVideo.prototype.setDisplayName = function(displayName) {
$editDisplayName.one("focusout", function () {
self.emitter.emit(UIEvents.NICKNAME_CHANGED, this.value);
$editDisplayName.hide();
$localDisplayName.show();
UIUtil.setVisibility($localDisplayName, true);
});
$editDisplayName.on('keydown', function (e) {

View File

@ -31,6 +31,7 @@ function RemoteVideo(user, VideoLayout, emitter) {
this.addRemoteVideoContainer();
this.connectionIndicator = new ConnectionIndicator(this, this.id);
this.setDisplayName();
this.bindHoverHandler();
this.flipX = false;
this.isLocal = false;
/**
@ -233,11 +234,9 @@ if (!interfaceConfig.filmStripOnly) {
RemoteVideo.prototype.addRemoteVideoMenu = function () {
var spanElement = document.createElement('span');
spanElement.className = 'remotevideomenu toolbar-icon right';
spanElement.className = 'remotevideomenu';
this.container
.querySelector('.videocontainer__toolbar')
.appendChild(spanElement);
this.container.appendChild(spanElement);
var menuElement = document.createElement('i');
menuElement.className = 'icon-menu-up';
@ -512,9 +511,10 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
/**
* Sets the display name for the given video span id.
*
* @param displayName the display name to set
*/
RemoteVideo.prototype.setDisplayName = function(displayName, key) {
RemoteVideo.prototype.setDisplayName = function(displayName) {
if (!this.container) {
console.warn( "Unable to set displayName - " + this.videoSpanId +
" does not exist");
@ -530,10 +530,6 @@ RemoteVideo.prototype.setDisplayName = function(displayName, key) {
if (displaynameSpan.text() !== displayName)
displaynameSpan.text(displayName);
}
else if (key && key.length > 0) {
var nameHtml = APP.translation.generateTranslationHTML(key);
$('#' + this.videoSpanId + '_name').html(nameHtml);
}
else
$('#' + this.videoSpanId + '_name').text(
interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
@ -541,7 +537,6 @@ RemoteVideo.prototype.setDisplayName = function(displayName, key) {
nameSpan = document.createElement('span');
nameSpan.className = 'displayname';
$('#' + this.videoSpanId)[0]
.querySelector('.videocontainer__toolbar')
.appendChild(nameSpan);
if (displayName && displayName.length > 0) {
@ -573,10 +568,18 @@ RemoteVideo.createContainer = function (spanId) {
container.id = spanId;
container.className = 'videocontainer';
let indicatorBar = document.createElement('div');
indicatorBar.className = "videocontainer__toptoolbar";
container.appendChild(indicatorBar);
let toolbar = document.createElement('div');
toolbar.className = "videocontainer__toolbar";
container.appendChild(toolbar);
let overlay = document.createElement('div');
overlay.className = "videocontainer__hoverOverlay";
container.appendChild(overlay);
var remotes = document.getElementById('remoteVideos');
return remotes.appendChild(container);
};

View File

@ -1,4 +1,4 @@
/* global $, APP, JitsiMeetJS, interfaceConfig */
/* global $, JitsiMeetJS, interfaceConfig */
import Avatar from "../avatar/Avatar";
import UIUtil from "../util/UIUtil";
import UIEvents from "../../../service/UI/UIEvents";
@ -21,11 +21,27 @@ const DISPLAY_VIDEO = 0;
const DISPLAY_AVATAR = 1;
/**
* Display mode constant used when neither video nor avatar is being displayed
* on the small video.
* on the small video. And we just show the display name.
* @type {number}
* @constant
*/
const DISPLAY_BLACKNESS = 2;
const DISPLAY_BLACKNESS_WITH_NAME = 2;
/**
* Display mode constant used when video is displayed and display name
* at the same time.
* @type {number}
* @constant
*/
const DISPLAY_VIDEO_WITH_NAME = 3;
/**
* Display mode constant used when neither video nor avatar is being displayed
* on the small video. And we just show the display name.
* @type {number}
* @constant
*/
const DISPLAY_AVATAR_WITH_NAME = 4;
function SmallVideo(VideoLayout) {
this.isAudioMuted = false;
@ -34,12 +50,7 @@ function SmallVideo(VideoLayout) {
this.videoStream = null;
this.audioStream = null;
this.VideoLayout = VideoLayout;
}
function setVisibility(selector, show) {
if (selector && selector.length > 0) {
selector.css("visibility", show ? "visible" : "hidden");
}
this.videoIsHovered = false;
}
/**
@ -60,18 +71,6 @@ SmallVideo.prototype.isVisible = function () {
return $('#' + this.videoSpanId).is(':visible');
};
SmallVideo.prototype.showDisplayName = function(isShow) {
var nameSpan = $('#' + this.videoSpanId + ' .displayname').get(0);
if (isShow) {
if (nameSpan && nameSpan.innerHTML && nameSpan.innerHTML.length)
nameSpan.setAttribute("style", "display:inline-block;");
}
else {
if (nameSpan)
nameSpan.setAttribute("style", "display:none;");
}
};
/**
* Enables / disables the device availability icons for this small video.
* @param {enable} set to {true} to enable and {false} to disable
@ -132,37 +131,6 @@ SmallVideo.prototype.getVideoType = function () {
return this.videoType;
};
/**
* Shows the presence status message for the given video.
*/
SmallVideo.prototype.setPresenceStatus = function (statusMsg) {
if (!this.container) {
// No container
return;
}
var statusSpan = $('#' + this.videoSpanId + '>span.status');
if (!statusSpan.length) {
//Add status span
statusSpan = document.createElement('span');
statusSpan.className = 'status';
statusSpan.id = this.videoSpanId + '_status';
$('#' + this.videoSpanId)[0].appendChild(statusSpan);
statusSpan = $('#' + this.videoSpanId + '>span.status');
}
// Display status
if (statusMsg && statusMsg.length) {
$('#' + this.videoSpanId + '_status').text(statusMsg);
statusSpan.get(0).setAttribute("style", "display:inline-block;");
}
else {
// Hide
statusSpan.get(0).setAttribute("style", "display:none;");
}
};
/**
* Creates an audio or video element for a particular MediaStream.
*/
@ -192,6 +160,29 @@ SmallVideo.getStreamElementID = function (stream) {
return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
};
/**
* Configures hoverIn/hoverOut handlers. Depends on connection indicator.
*/
SmallVideo.prototype.bindHoverHandler = function () {
// Add hover handler
$(this.container).hover(
() => {
this.videoIsHovered = true;
this.updateView();
},
() => {
this.videoIsHovered = false;
this.updateView();
}
);
if (this.connectionIndicator) {
this.connectionIndicator.addPopoverHoverListener(
() => {
this.updateView();
});
}
};
/**
* Updates the data for the indicator
* @param id the id of the indicator
@ -395,6 +386,16 @@ SmallVideo.prototype.$avatar = function () {
return $('#' + this.videoSpanId + ' .userAvatar');
};
/**
* Returns the display name element, which appears on the video thumbnail.
*
* @return {jQuery} a jQuery selector pointing to the display name element of
* the video thumbnail
*/
SmallVideo.prototype.$displayName = function () {
return $('#' + this.videoSpanId + ' .displayname');
};
/**
* Enables / disables the css responsible for focusing/pinning a video
* thumbnail.
@ -445,19 +446,35 @@ SmallVideo.prototype.isVideoPlayable = function() {
* Determines what should be display on the thumbnail.
*
* @return {number} one of <tt>DISPLAY_VIDEO</tt>,<tt>DISPLAY_AVATAR</tt>
* or <tt>DISPLAY_BLACKNESS</tt>.
* or <tt>DISPLAY_BLACKNESS_WITH_NAME</tt>.
*/
SmallVideo.prototype.selectDisplayMode = function() {
// Display name is always and only displayed when user is on the stage
if (this.isCurrentlyOnLargeVideo()) {
return DISPLAY_BLACKNESS;
return DISPLAY_BLACKNESS_WITH_NAME;
} else if (this.isVideoPlayable() && this.selectVideoElement().length) {
return DISPLAY_VIDEO;
// check hovering and change state to video with name
return this._isHovered() ?
DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
} else {
return DISPLAY_AVATAR;
// check hovering and change state to avatar with name
return this._isHovered() ?
DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
}
};
/**
* Checks whether current video is considered hovered. Currently it is hovered
* if the mouse is over the video, or if the connection
* indicator is shown(hovered).
* @private
*/
SmallVideo.prototype._isHovered = function () {
return this.videoIsHovered
|| (this.connectionIndicator
&& this.connectionIndicator.popover.popoverIsHovered);
};
/**
* Hides or shows the user's avatar.
* This update assumes that large video had been updated and we will
@ -479,10 +496,25 @@ SmallVideo.prototype.updateView = function () {
// Determine whether video, avatar or blackness should be displayed
let displayMode = this.selectDisplayMode();
// Show/hide video
setVisibility(this.selectVideoElement(), displayMode === DISPLAY_VIDEO);
// Show/hide the avatar
setVisibility(this.$avatar(), displayMode === DISPLAY_AVATAR);
// Show/hide video.
UIUtil.setVisibility( this.selectVideoElement(),
(displayMode === DISPLAY_VIDEO
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
// Show/hide the avatar.
UIUtil.setVisibility( this.$avatar(),
(displayMode === DISPLAY_AVATAR
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
// Show/hide the display name.
UIUtil.setVisibility( this.$displayName(),
(displayMode === DISPLAY_BLACKNESS_WITH_NAME
|| displayMode === DISPLAY_VIDEO_WITH_NAME
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
// show hide overlay when there is a video or avatar under
// the display name
UIUtil.setVisibility( $('#' + this.videoSpanId
+ ' .videocontainer__hoverOverlay'),
(displayMode === DISPLAY_AVATAR_WITH_NAME
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
};
SmallVideo.prototype.avatarChanged = function (avatarUrl) {
@ -519,13 +551,21 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
return;
}
var indicatorSpan = this.getIndicatorSpan({
id: 'dominantspeakerindicator',
content: '<i id="indicatoricon" class="fa fa-bullhorn"></i>',
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'
});
indicatorSpan.style.display = show ? "" : "none";
if (show) {
indicatorSpan.classList.add('show');
} else {
indicatorSpan.classList.remove('show');
}
};
/**
@ -539,43 +579,21 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
return;
}
var indicatorSpan = this.getIndicatorSpan({
id: 'raisehandindicator',
content: '<i id="indicatoricon" class="icon-raised-hand"></i>',
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'
});
indicatorSpan.style.display = show ? "" : "none";
};
/**
* Gets (creating if necessary) the "indicator" span for this SmallVideo.
*
* @param options.id {String} element ID
* @param options.content {String} HTML content of the indicator
* @param options.tooltip {String} The key that should be passed to tooltip
*
* @returns {HTMLElement} DOM represention of the indicator
*/
SmallVideo.prototype.getIndicatorSpan = function(options) {
var indicator = this.container.querySelector('#' + options.id);
if (indicator) {
return indicator;
if (show) {
indicatorSpan.classList.add('show');
} else {
indicatorSpan.classList.remove('show');
}
indicator = document.createElement('span');
indicator.className = 'indicator';
indicator.id = options.id;
indicator.innerHTML = options.content;
UIUtil.setTooltip(indicator, options.tooltip, "top");
APP.translation.translateElement($(indicator));
this.container.appendChild(indicator);
return indicator;
};
/**

View File

@ -449,15 +449,6 @@ var VideoLayout = {
}
},
/**
* Shows the presence status message for the given video.
*/
setPresenceStatus (id, statusMsg) {
let remoteVideo = remoteVideos[id];
if (remoteVideo)
remoteVideo.setPresenceStatus(statusMsg);
},
/**
* Shows a visual indicator for the moderator of the conference.
* On local or remote participants.