diff --git a/conference.js b/conference.js index d27ff4278..b10f6c556 100644 --- a/conference.js +++ b/conference.js @@ -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(); diff --git a/css/_variables.scss b/css/_variables.scss index 7e0ec2c19..fc1a2a515 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -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: #48CC8C; $audioLevelShadow: rgba(9, 36, 77, 0.9); $videoStateIndicatorColor: $defaultColor; $videoStateIndicatorBackground: $toolbarBackground; diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 7c31960ba..01e97cbc0 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -58,18 +58,25 @@ /** * The toolbar of the video thumbnail. */ -.videocontainer__toolbar { +.videocontainer__toolbar, +.videocontainer__toptoolbar { position: absolute; - bottom: 0; left: 0; z-index: 1; width: 100%; box-sizing: border-box; // Includes the padding in the 100% width. height: $thumbnailToolbarHeight; - max-height: 100%; padding: 0 5px 0 5px; } +.videocontainer__toolbar { + bottom: 0; +} + +.videocontainer__toptoolbar { + top: 0; +} + #remoteVideos .videocontainer.videoContainerFocused, #remoteVideos .videocontainer:hover { cursor: hand; @@ -201,72 +208,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; } @@ -279,7 +224,6 @@ pointer-events: auto !important; } -.videocontainer>a.status, .videocontainer>a.displayname { display: inline-block; position: absolute; @@ -324,25 +268,81 @@ 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 { + font-size: 8pt; + text-align: center; + line-height: $thumbnailToolbarHeight; + 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 { + width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; + height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; + line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; + margin-left: 5px; // TOP toolbar padding; + } + + .connection.connection_empty + { + color: #8B8B8B;/*#FFFFFF*/ + overflow: hidden; + } + + .connection.connection_lost + { + color: #8B8B8B; + overflow: visible; + } + + .connection.connection_full + { + color: #FFFFFF;/*#15A1ED*/ + overflow: hidden; + } + + .connection, + .icon-connection, + .icon-connection-lost { + font-size: 6pt; + line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; + } + + .connection + { + position: absolute; + left: 0px; + top: 0px; + border: 0px; + } +} + +.remotevideomenu +{ + display: inline-block; + position: absolute; + top: 0px; + right: 0; + margin: 7px; + z-index: 3; + width: 18px; + height: 13px; + color: #FFF; + font-size: 8pt; } /** @@ -385,12 +385,6 @@ } } -#indicatoricon { - width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; - height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; - line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; -} - #reloadPresentation { display: none; position: absolute; diff --git a/index.html b/index.html index 3426833d3..23308b83b 100644 --- a/index.html +++ b/index.html @@ -254,6 +254,7 @@
+ diff --git a/modules/UI/UI.js b/modules/UI/UI.js index b922bca71..76a919988 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -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 diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js index eaf7226b8..ace1dcea7 100644 --- a/modules/UI/util/UIUtil.js +++ b/modules/UI/util/UIUtil.js @@ -136,7 +136,7 @@ const TOOLTIP_POSITIONS = { element.setAttribute('data-i18n', '[content]' + key); APP.translation.translateElement($(element)); - } + } }, /** @@ -388,6 +388,45 @@ 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} #${indicatorId}]`); + let indicatorSpan; + + if (indicators.length <= 0) { + indicatorSpan = document.createElement('span'); + indicatorSpan.className = 'indicator'; + indicatorSpan.id = indicatorId; + + indicatorSpan.innerHTML = opts.content; + + this.setTooltip(indicatorSpan, opts.tooltip, "top"); + APP.translation.translateElement($(indicatorSpan)); + + document.getElementById(videoSpanId) + .querySelector('.videocontainer__toptoolbar') + .appendChild(indicatorSpan); + } else { + indicatorSpan = indicators[0]; + } + + return indicatorSpan; } }; diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index d8312cb1e..59479e95b 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -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(); } @@ -247,6 +249,7 @@ ConnectionIndicator.prototype.showMore = function () { function createIcon(classes, iconClass) { var icon = document.createElement("span"); + icon.classList.add("indicatoricon"); for(var i in classes) { icon.classList.add(classes[i]); } @@ -259,18 +262,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: "", - skin: "black", - onBeforePosition: el => APP.translation.translateElement(el) - }); + let indicatorId = 'connectionindicator'; + let element = UIUtil.getVideoThumbnailIndicatorSpan({ + videoSpanId: this.videoContainer.videoSpanId, + indicatorId + }); + element.classList.add('hide'); + this.connectionIndicatorContainer = element; + + let popoverContent = ( + `` + ); + 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 diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 7620e93bc..00e99712c 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -233,11 +233,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'; @@ -569,6 +567,10 @@ 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); diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 1d57ebdf2..43dda3303 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -126,37 +126,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. */ @@ -528,13 +497,19 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) { return; } - var indicatorSpan = this.getIndicatorSpan({ - id: 'dominantspeakerindicator', + let indicatorSpanId = "dominantspeakerindicator"; + let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({ + videoSpanId: this.videoSpanId, + indicatorId: indicatorSpanId, content: '', tooltip: 'speaker' }); - indicatorSpan.style.display = show ? "" : "none"; + if (show) { + indicatorSpan.classList.add('hide'); + } else { + indicatorSpan.classList.remove('hide') + } }; /** @@ -548,43 +523,19 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) { return; } - var indicatorSpan = this.getIndicatorSpan({ - id: 'raisehandindicator', + let indicatorSpanId = "raisehandindicator"; + 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('hide'); + } else { + indicatorSpan.classList.remove('hide') } - - 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; }; /** diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 749dd23ec..a38a4b2ca 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -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.