From 3fe43abdea5407d8fc2c0e3a1a714ecddbccb56c Mon Sep 17 00:00:00 2001 From: yanas Date: Thu, 20 Oct 2016 14:28:10 -0500 Subject: [PATCH 01/17] Move the display name to the center --- css/_videolayout_default.scss | 7 ++++--- modules/UI/util/UIUtil.js | 12 +++++++++++ modules/UI/videolayout/LocalVideo.js | 1 - modules/UI/videolayout/RemoteVideo.js | 10 +++------ modules/UI/videolayout/SmallVideo.js | 29 ++++++++++++++++++--------- 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 9333db78c..7c31960ba 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -67,7 +67,6 @@ box-sizing: border-box; // Includes the padding in the 100% width. height: $thumbnailToolbarHeight; max-height: 100%; - background-color: rgba(0, 0, 0, 0.5); padding: 0 5px 0 5px; } @@ -176,8 +175,10 @@ .videocontainer .editdisplayname { display: inline-block; position: absolute; - left: 30%; - width: 40%; + left: 10%; + width: 80%; + top: 50%; + margin-top: -12px; color: $participantNameColor; text-align: center; text-overflow: ellipsis; diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js index fe4d1f739..eaf7226b8 100644 --- a/modules/UI/util/UIUtil.js +++ b/modules/UI/util/UIUtil.js @@ -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) { diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index 0aadf0e81..4c9a44651 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -70,7 +70,6 @@ LocalVideo.prototype.setDisplayName = function(displayName) { nameSpan = document.createElement('span'); nameSpan.className = 'displayname'; document.getElementById(this.videoSpanId) - .querySelector('.videocontainer__toolbar') .appendChild(nameSpan); diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 359d191d3..7620e93bc 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -512,9 +512,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 +531,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 +538,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) { diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index eb19178b2..1d57ebdf2 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -36,12 +36,6 @@ function SmallVideo(VideoLayout) { this.VideoLayout = VideoLayout; } -function setVisibility(selector, show) { - if (selector && selector.length > 0) { - selector.css("visibility", show ? "visible" : "hidden"); - } -} - /** * Returns the identifier of this small video. * @@ -395,6 +389,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. @@ -479,10 +483,15 @@ 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); + // Show/hide the avatar. + UIUtil.setVisibility( this.$avatar(), + displayMode === DISPLAY_AVATAR); + // Show/hide the display name. + UIUtil.setVisibility( this.$displayName(), + displayMode === DISPLAY_BLACKNESS); }; SmallVideo.prototype.avatarChanged = function (avatarUrl) { From a17a98991c4212a76a2a7e9386fb6475a46bcb46 Mon Sep 17 00:00:00 2001 From: yanas Date: Tue, 25 Oct 2016 22:05:32 -0500 Subject: [PATCH 02/17] Ongoing work on video thumbnail layout --- conference.js | 4 - css/_variables.scss | 5 +- css/_videolayout_default.scss | 172 +++++++++--------- index.html | 1 + modules/UI/UI.js | 4 - modules/UI/util/UIUtil.js | 41 ++++- modules/UI/videolayout/ConnectionIndicator.js | 35 ++-- modules/UI/videolayout/RemoteVideo.js | 10 +- modules/UI/videolayout/SmallVideo.js | 83 ++------- modules/UI/videolayout/VideoLayout.js | 9 - 10 files changed, 171 insertions(+), 193 deletions(-) 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. From 09e3fb9917272b123f8af656f12fb38d7a28b8a6 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 12:51:51 +0300 Subject: [PATCH 03/17] Fixed hack with displayname margin --- css/_videolayout_default.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 01e97cbc0..cf7ee9738 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -185,7 +185,7 @@ left: 10%; width: 80%; top: 50%; - margin-top: -12px; + @include transform(translateY(-40%)); color: $participantNameColor; text-align: center; text-overflow: ellipsis; From 323684c5fe3e9628dd113f32601a1f521ab0a9f9 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 15:18:48 +0300 Subject: [PATCH 04/17] fix conflicts after rebase --- css/_videolayout_default.scss | 1 + modules/UI/util/UIUtil.js | 2 +- modules/UI/videolayout/ConnectionIndicator.js | 3 +-- modules/UI/videolayout/SmallVideo.js | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index cf7ee9738..df07b3fb1 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -280,6 +280,7 @@ font-size: 8pt; text-align: center; line-height: $thumbnailToolbarHeight; + display: none; padding: 0; margin-right: 5px; float: left; diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js index ace1dcea7..ed9235c1f 100644 --- a/modules/UI/util/UIUtil.js +++ b/modules/UI/util/UIUtil.js @@ -406,7 +406,7 @@ const TOOLTIP_POSITIONS = { getVideoThumbnailIndicatorSpan(opts = {}) { let indicatorId = opts.indicatorId; let videoSpanId = opts.videoSpanId; - let indicators = $(`#${videoSpanId} #${indicatorId}]`); + let indicators = $(`#${videoSpanId} [id="${indicatorId}"]`); let indicatorSpan; if (indicators.length <= 0) { diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index 59479e95b..f7836e95a 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -267,13 +267,12 @@ ConnectionIndicator.prototype.create = function () { videoSpanId: this.videoContainer.videoSpanId, indicatorId }); - element.classList.add('hide'); this.connectionIndicatorContainer = element; let popoverContent = ( `
` ); - this.popover = new JitsiPopover(element, { + this.popover = new JitsiPopover($(element), { content: popoverContent, skin: "black", onBeforePosition: el => APP.translation.translateElement(el) diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 43dda3303..3a491a81f 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -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"; @@ -506,9 +506,9 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) { }); if (show) { - indicatorSpan.classList.add('hide'); + indicatorSpan.classList.add('show'); } else { - indicatorSpan.classList.remove('hide') + indicatorSpan.classList.remove('show'); } }; @@ -532,9 +532,9 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) { }); if (show) { - indicatorSpan.classList.add('hide'); + indicatorSpan.classList.add('show'); } else { - indicatorSpan.classList.remove('hide') + indicatorSpan.classList.remove('show'); } }; From 698b3caeb8c466158683aa9897d9fefaf2a181f6 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 15:58:27 +0300 Subject: [PATCH 05/17] fix styles in connection indicators --- css/_videolayout_default.scss | 20 ++++++++++++++------ modules/UI/videolayout/SmallVideo.js | 8 ++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index df07b3fb1..1f7b97434 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -65,16 +65,20 @@ z-index: 1; width: 100%; box-sizing: border-box; // Includes the padding in the 100% width. - height: $thumbnailToolbarHeight; - padding: 0 5px 0 5px; } .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; } #remoteVideos .videocontainer.videoContainerFocused, @@ -277,6 +281,7 @@ } .videocontainer__toptoolbar span.indicator { + position: relative; font-size: 8pt; text-align: center; line-height: $thumbnailToolbarHeight; @@ -292,10 +297,13 @@ border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor; .indicatoricon { - width: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; - height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; - line-height: $thumbnailIndicatorSize - 2*$thumbnailIndicatorBorder; - margin-left: 5px; // TOP toolbar padding; + position: absolute; + top: 50%; + left: 0; + @include transform(translateY(-50%)); + width: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder; + height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder; + line-height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder; } .connection.connection_empty diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 3a491a81f..535995d67 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -498,10 +498,12 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) { } let indicatorSpanId = "dominantspeakerindicator"; + let content = ``; let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({ videoSpanId: this.videoSpanId, indicatorId: indicatorSpanId, - content: '', + content, tooltip: 'speaker' }); @@ -524,10 +526,12 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) { } let indicatorSpanId = "raisehandindicator"; + let content = ``; let indicatorSpan = UIUtil.getVideoThumbnailIndicatorSpan({ indicatorId: indicatorSpanId, videoSpanId: this.videoSpanId, - content: '', + content, tooltip: 'raisedHand' }); From 69b79b7687016e379630da98c4bb74982bdbeb72 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 17:50:39 +0300 Subject: [PATCH 06/17] Fix icon styles --- css/_mixins.scss | 9 +++ css/_videolayout_default.scss | 58 ++++++++++--------- modules/UI/util/UIUtil.js | 10 +++- modules/UI/videolayout/ConnectionIndicator.js | 20 ++++--- 4 files changed, 61 insertions(+), 36 deletions(-) diff --git a/css/_mixins.scss b/css/_mixins.scss index ba1dedb8d..89ffa27c9 100644 --- a/css/_mixins.scss +++ b/css/_mixins.scss @@ -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%; diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 1f7b97434..107c02fcb 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -306,37 +306,43 @@ line-height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder; } - .connection.connection_empty - { - color: #8B8B8B;/*#FFFFFF*/ - overflow: hidden; + .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; + } } - .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; } } diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js index ed9235c1f..8e7d74fc5 100644 --- a/modules/UI/util/UIUtil.js +++ b/modules/UI/util/UIUtil.js @@ -414,10 +414,14 @@ const TOOLTIP_POSITIONS = { indicatorSpan.className = 'indicator'; indicatorSpan.id = indicatorId; - indicatorSpan.innerHTML = opts.content; + if(opts.content) { + indicatorSpan.innerHTML = opts.content; + } - this.setTooltip(indicatorSpan, opts.tooltip, "top"); - APP.translation.translateElement($(indicatorSpan)); + if (opts.tooltip) { + this.setTooltip(indicatorSpan, opts.tooltip, "top"); + APP.translation.translateElement($(indicatorSpan)); + } document.getElementById(videoSpanId) .querySelector('.videocontainer__toptoolbar') diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index f7836e95a..f4d670b8f 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -249,7 +249,6 @@ 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]); } @@ -267,6 +266,7 @@ ConnectionIndicator.prototype.create = function () { videoSpanId: this.videoContainer.videoSpanId, indicatorId }); + element.classList.add('show'); this.connectionIndicatorContainer = element; let popoverContent = ( @@ -289,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); }; /** From 8d80e13e31fee5cf8db75ba83db006be95d60f0d Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 18:33:49 +0300 Subject: [PATCH 07/17] Fix connection indicator bars --- modules/UI/videolayout/ConnectionIndicator.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index f4d670b8f..7ecd83ec9 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -34,12 +34,12 @@ function ConnectionIndicator(videoContainer, videoId) { * 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) { From 1e24be6dd4ed7553cbefdf7d0300cb857f9f2ab8 Mon Sep 17 00:00:00 2001 From: Ilya Daynatovich Date: Wed, 26 Oct 2016 19:17:59 +0300 Subject: [PATCH 08/17] Fix editing the name --- modules/UI/videolayout/LocalVideo.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index 4c9a44651..f9a621210 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -103,7 +103,6 @@ LocalVideo.prototype.setDisplayName = function(displayName) { APP.translation.translateElement($(editableText)); this.container - .querySelector('.videocontainer__toolbar') .appendChild(editableText); var self = this; From 5cead57723e08dc3aad3befb3040ffb91c9feeab Mon Sep 17 00:00:00 2001 From: damencho Date: Wed, 26 Oct 2016 15:45:51 -0500 Subject: [PATCH 09/17] Reverts hover over small video to show display name. --- modules/UI/videolayout/LocalVideo.js | 1 + modules/UI/videolayout/RemoteVideo.js | 1 + modules/UI/videolayout/SmallVideo.js | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index f9a621210..d806c6efb 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -11,6 +11,7 @@ function LocalVideo(VideoLayout, emitter) { this.videoSpanId = "localVideoContainer"; this.container = $("#localVideoContainer").get(0); this.localVideoId = null; + this.bindHoverHandler(); if(config.enableLocalVideoFlip) this._buildContextMenu(); this.isLocal = true; diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 00e99712c..4633d7f7f 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -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; /** diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 535995d67..561b3be90 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -155,6 +155,26 @@ SmallVideo.getStreamElementID = function (stream) { return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId(); }; +/** + * Configures hoverIn/hoverOut handlers. + */ +SmallVideo.prototype.bindHoverHandler = function () { + // Add hover handler + var self = this; + $(this.container).hover( + function () { + self.showDisplayName(true); + }, + function () { + // If the video has been "pinned" by the user we want to + // keep the display name on place. + if (!self.VideoLayout.isLargeVideoVisible() || + !self.VideoLayout.isCurrentlyOnLarge(self.id)) + self.showDisplayName(false); + } + ); +}; + /** * Updates the data for the indicator * @param id the id of the indicator From 7acda0302472edb07a555d15f2a2d481890b4f07 Mon Sep 17 00:00:00 2001 From: damencho Date: Wed, 26 Oct 2016 15:47:28 -0500 Subject: [PATCH 10/17] Adds an overlay to dim videos when showing displayname. --- css/_videolayout_default.scss | 11 ++++++++++- index.html | 1 + modules/UI/videolayout/RemoteVideo.js | 4 ++++ modules/UI/videolayout/SmallVideo.js | 8 ++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 107c02fcb..e2dfca1d8 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -62,7 +62,7 @@ .videocontainer__toptoolbar { position: absolute; left: 0; - z-index: 1; + z-index: 3; width: 100%; box-sizing: border-box; // Includes the padding in the 100% width. } @@ -81,6 +81,15 @@ height: $thumbnailIndicatorSize + $toolbarPadding; } +.videocontainer__overlay { + position: relative; + width: 100%; + height: 100%; + display: none; + background: rgba(0,0,0,.6); + z-index: 2; +} + #remoteVideos .videocontainer.videoContainerFocused, #remoteVideos .videocontainer:hover { cursor: hand; diff --git a/index.html b/index.html index 23308b83b..d42645d6f 100644 --- a/index.html +++ b/index.html @@ -255,6 +255,7 @@
+
diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 4633d7f7f..2d8163790 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -576,6 +576,10 @@ RemoteVideo.createContainer = function (spanId) { toolbar.className = "videocontainer__toolbar"; container.appendChild(toolbar); + let overlay = document.createElement('div'); + overlay.className = "videocontainer__overlay"; + container.appendChild(overlay); + var remotes = document.getElementById('remoteVideos'); return remotes.appendChild(container); }; diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 561b3be90..6a21c83cd 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -163,9 +163,17 @@ SmallVideo.prototype.bindHoverHandler = function () { var self = this; $(this.container).hover( function () { + if (!self.VideoLayout.isCurrentlyOnLarge(self.id)) { + $('#' + self.videoSpanId + ' .videocontainer__overlay') + .removeClass("hide") + .addClass("show-inline"); + } self.showDisplayName(true); }, function () { + $('#' + self.videoSpanId + ' .videocontainer__overlay') + .removeClass("show-inline") + .addClass("hide"); // If the video has been "pinned" by the user we want to // keep the display name on place. if (!self.VideoLayout.isLargeVideoVisible() || From 3ae299cf2b981d7631da490c4d488eb851a8ae90 Mon Sep 17 00:00:00 2001 From: damencho Date: Wed, 26 Oct 2016 17:18:36 -0500 Subject: [PATCH 11/17] Fixes comments. --- modules/UI/videolayout/SmallVideo.js | 31 ++++++++-------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index 6a21c83cd..c919c5f64 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -54,18 +54,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 @@ -160,25 +148,24 @@ SmallVideo.getStreamElementID = function (stream) { */ SmallVideo.prototype.bindHoverHandler = function () { // Add hover handler - var self = this; $(this.container).hover( - function () { - if (!self.VideoLayout.isCurrentlyOnLarge(self.id)) { - $('#' + self.videoSpanId + ' .videocontainer__overlay') + () => { + if (!this.VideoLayout.isCurrentlyOnLarge(this.id)) { + $('#' + this.videoSpanId + ' .videocontainer__overlay') .removeClass("hide") .addClass("show-inline"); + UIUtil.setVisibility(this.$displayName(), true); } - self.showDisplayName(true); }, - function () { - $('#' + self.videoSpanId + ' .videocontainer__overlay') + () => { + $('#' + this.videoSpanId + ' .videocontainer__overlay') .removeClass("show-inline") .addClass("hide"); // If the video has been "pinned" by the user we want to // keep the display name on place. - if (!self.VideoLayout.isLargeVideoVisible() || - !self.VideoLayout.isCurrentlyOnLarge(self.id)) - self.showDisplayName(false); + if (!this.VideoLayout.isLargeVideoVisible() || + !this.VideoLayout.isCurrentlyOnLarge(this.id)) + UIUtil.setVisibility(this.$displayName(), false); } ); }; From fec8f4e005b87c17b614cc1d4b5d1c8076f7a2bd Mon Sep 17 00:00:00 2001 From: damencho Date: Wed, 26 Oct 2016 17:36:07 -0500 Subject: [PATCH 12/17] Fixes an issue with mixing visibility functions for elements. In small video we use UIUtil.setVisibility, so we should not use jquery show/hide for the same element. --- modules/UI/videolayout/LocalVideo.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index d806c6efb..021f026b6 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -114,7 +114,7 @@ LocalVideo.prototype.setDisplayName = function(displayName) { e.preventDefault(); e.stopPropagation(); - $localDisplayName.hide(); + UIUtil.setVisibility($localDisplayName, false); $editDisplayName.show(); $editDisplayName.focus(); $editDisplayName.select(); @@ -122,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) { From 2807346bdf49c079c81e316c2f03d65cd57bff64 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Oct 2016 13:17:17 -0500 Subject: [PATCH 13/17] Makes decision what to show in avatar consistent (in updateView). --- css/_videolayout_default.scss | 2 +- modules/UI/util/JitsiPopover.js | 13 +++ modules/UI/videolayout/ConnectionIndicator.js | 7 ++ modules/UI/videolayout/LocalVideo.js | 2 +- modules/UI/videolayout/SmallVideo.js | 86 +++++++++++++------ 5 files changed, 84 insertions(+), 26 deletions(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index e2dfca1d8..6bea52c76 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -85,7 +85,7 @@ position: relative; width: 100%; height: 100%; - display: none; + visibility: hidden; background: rgba(0,0,0,.6); z-index: 2; } diff --git a/modules/UI/util/JitsiPopover.js b/modules/UI/util/JitsiPopover.js index f49c4ea50..26608ca8d 100644 --- a/modules/UI/util/JitsiPopover.js +++ b/modules/UI/util/JitsiPopover.js @@ -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. */ diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index 7ecd83ec9..d73be9c7f 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -439,4 +439,11 @@ ConnectionIndicator.prototype.updateResolutionIndicator = function () { } }; +/** + * Adds a hover listener to the popover. + */ +ConnectionIndicator.prototype.addPopoverHoverListener = function (listener) { + this.popover.addOnHoverPopover(listener); +}; + export default ConnectionIndicator; diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index 021f026b6..ff1c9ca22 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -11,6 +11,7 @@ function LocalVideo(VideoLayout, emitter) { this.videoSpanId = "localVideoContainer"; this.container = $("#localVideoContainer").get(0); this.localVideoId = null; + this.createConnectionIndicator(); this.bindHoverHandler(); if(config.enableLocalVideoFlip) this._buildContextMenu(); @@ -28,7 +29,6 @@ function LocalVideo(VideoLayout, emitter) { // Set default display name. this.setDisplayName(); - this.createConnectionIndicator(); this.addAudioLevelIndicator(); } diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index c919c5f64..e1f1357e3 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -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,6 +50,7 @@ function SmallVideo(VideoLayout) { this.videoStream = null; this.audioStream = null; this.VideoLayout = VideoLayout; + this.videoIsHovered = false; } /** @@ -144,30 +161,26 @@ SmallVideo.getStreamElementID = function (stream) { }; /** - * Configures hoverIn/hoverOut handlers. + * Configures hoverIn/hoverOut handlers. Depends on connection indicator. */ SmallVideo.prototype.bindHoverHandler = function () { // Add hover handler $(this.container).hover( () => { - if (!this.VideoLayout.isCurrentlyOnLarge(this.id)) { - $('#' + this.videoSpanId + ' .videocontainer__overlay') - .removeClass("hide") - .addClass("show-inline"); - UIUtil.setVisibility(this.$displayName(), true); - } + this.videoIsHovered = true; + this.updateView(); }, () => { - $('#' + this.videoSpanId + ' .videocontainer__overlay') - .removeClass("show-inline") - .addClass("hide"); - // If the video has been "pinned" by the user we want to - // keep the display name on place. - if (!this.VideoLayout.isLargeVideoVisible() || - !this.VideoLayout.isCurrentlyOnLarge(this.id)) - UIUtil.setVisibility(this.$displayName(), false); + this.videoIsHovered = false; + this.updateView(); } ); + if (this.connectionIndicator) { + this.connectionIndicator.addPopoverHoverListener( + () => { + this.updateView(); + }); + } }; /** @@ -433,19 +446,34 @@ SmallVideo.prototype.isVideoPlayable = function() { * Determines what should be display on the thumbnail. * * @return {number} one of DISPLAY_VIDEO,DISPLAY_AVATAR - * or DISPLAY_BLACKNESS. + * or DISPLAY_BLACKNESS_WITH_NAME. */ 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.popover.popoverIsHovered; +}; + /** * Hides or shows the user's avatar. * This update assumes that large video had been updated and we will @@ -469,13 +497,23 @@ SmallVideo.prototype.updateView = function () { let displayMode = this.selectDisplayMode(); // Show/hide video. UIUtil.setVisibility( this.selectVideoElement(), - displayMode === DISPLAY_VIDEO); + (displayMode === DISPLAY_VIDEO + || displayMode === DISPLAY_VIDEO_WITH_NAME)); // Show/hide the avatar. UIUtil.setVisibility( this.$avatar(), - displayMode === DISPLAY_AVATAR); + (displayMode === DISPLAY_AVATAR + || displayMode === DISPLAY_AVATAR_WITH_NAME)); // Show/hide the display name. UIUtil.setVisibility( this.$displayName(), - displayMode === DISPLAY_BLACKNESS); + (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__overlay'), + (displayMode === DISPLAY_AVATAR_WITH_NAME + || displayMode === DISPLAY_VIDEO_WITH_NAME)); }; SmallVideo.prototype.avatarChanged = function (avatarUrl) { From 328ff54423fe02aefc6205ee6dd7667059719296 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Oct 2016 14:08:06 -0500 Subject: [PATCH 14/17] Fixes undefined error and shared video. --- modules/UI/shared_video/SharedVideo.js | 2 +- modules/UI/videolayout/SmallVideo.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index 064e2f0c5..8991de840 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -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; } diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index e1f1357e3..bdf82c10e 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -471,7 +471,8 @@ SmallVideo.prototype.selectDisplayMode = function() { */ SmallVideo.prototype._isHovered = function () { return this.videoIsHovered - || this.connectionIndicator.popover.popoverIsHovered; + || (this.connectionIndicator + && this.connectionIndicator.popover.popoverIsHovered); }; /** From e3edef2999f5e27d64c3927814b02b0ed8d9194c Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Oct 2016 14:32:22 -0500 Subject: [PATCH 15/17] Renames videocontainer overlay to hoverOverlay. --- css/_videolayout_default.scss | 2 +- index.html | 2 +- modules/UI/videolayout/RemoteVideo.js | 2 +- modules/UI/videolayout/SmallVideo.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/css/_videolayout_default.scss b/css/_videolayout_default.scss index 6bea52c76..ae96ae351 100644 --- a/css/_videolayout_default.scss +++ b/css/_videolayout_default.scss @@ -81,7 +81,7 @@ height: $thumbnailIndicatorSize + $toolbarPadding; } -.videocontainer__overlay { +.videocontainer__hoverOverlay { position: relative; width: 100%; height: 100%; diff --git a/index.html b/index.html index d42645d6f..0b48e162c 100644 --- a/index.html +++ b/index.html @@ -255,7 +255,7 @@
-
+
diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 2d8163790..87015baa8 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -577,7 +577,7 @@ RemoteVideo.createContainer = function (spanId) { container.appendChild(toolbar); let overlay = document.createElement('div'); - overlay.className = "videocontainer__overlay"; + overlay.className = "videocontainer__hoverOverlay"; container.appendChild(overlay); var remotes = document.getElementById('remoteVideos'); diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index bdf82c10e..04de14658 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -512,7 +512,7 @@ SmallVideo.prototype.updateView = function () { // show hide overlay when there is a video or avatar under // the display name UIUtil.setVisibility( $('#' + this.videoSpanId - + ' .videocontainer__overlay'), + + ' .videocontainer__hoverOverlay'), (displayMode === DISPLAY_AVATAR_WITH_NAME || displayMode === DISPLAY_VIDEO_WITH_NAME)); }; From 131d5cc2563734a0800bf8499cae56f84d1319b6 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Oct 2016 15:27:28 -0500 Subject: [PATCH 16/17] Change the colour of the connection indicator badge. --- css/_variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/_variables.scss b/css/_variables.scss index fc1a2a515..7050edeea 100644 --- a/css/_variables.scss +++ b/css/_variables.scss @@ -46,7 +46,7 @@ $thumbnailPictogramColor: #fff; $dominantSpeakerBg: #165ecc; $raiseHandBg: #D6D61E; $audioLevelBg: #44A5FF; -$connectionIndicatorBg: #48CC8C; +$connectionIndicatorBg: #165ecc; $audioLevelShadow: rgba(9, 36, 77, 0.9); $videoStateIndicatorColor: $defaultColor; $videoStateIndicatorBackground: $toolbarBackground; From 9764fe52dea7679bb4161f00832579f280728285 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Oct 2016 16:56:32 -0500 Subject: [PATCH 17/17] Removed not needed setting of the quality to 0. We now just hide the icon with values and show the interrupted one. Calling this one was causing troubles like flickering and stats popover not able to hide, once shown. On hover we are calling updateView which ends to this call which destroy and create the popover, which maybe is leading to this problems. --- modules/UI/videolayout/ConnectionIndicator.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/UI/videolayout/ConnectionIndicator.js b/modules/UI/videolayout/ConnectionIndicator.js index d73be9c7f..829c7c97d 100644 --- a/modules/UI/videolayout/ConnectionIndicator.js +++ b/modules/UI/videolayout/ConnectionIndicator.js @@ -332,7 +332,6 @@ ConnectionIndicator.prototype.updateConnectionStatusIndicator $(this.interruptedIndicator).show(); $(this.emptyIcon).hide(); $(this.fullIcon).hide(); - this.updateConnectionQuality(0 /* zero bars */); } };