diff --git a/css/jitsi_popover.css b/css/jitsi_popover.css index 545ebf1c4..fcb6484f0 100644 --- a/css/jitsi_popover.css +++ b/css/jitsi_popover.css @@ -16,7 +16,6 @@ border-radius: 6px; /*-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);*/ /*box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);*/ - white-space: normal; margin-top: -10px; margin-bottom: 35px; } @@ -30,7 +29,6 @@ .jitsipopover-content { padding: 9px 14px; font-size: 10pt; - white-space:pre-wrap; text-align: center; } diff --git a/css/popup_menu.css b/css/popup_menu.css index 300d95f4b..ad1123508 100644 --- a/css/popup_menu.css +++ b/css/popup_menu.css @@ -1,32 +1,15 @@ /*Initialize*/ ul.popupmenu { - display:none; - position: absolute; - padding:10px; - margin: 0; - bottom: 0; - margin-bottom: 35px; - padding-bottom: 10px; - padding-top: 10px; - right: 10px; - left: -5px; width: 100px; - background-color: rgba(0,0,0,0.9); - border: 1px solid rgba(256, 256, 256, 0.2); - border-radius:8px; -} - -ul.popupmenu:after { - content: url('../images/popupPointer.png'); - display: block; - position: absolute; - bottom: -8px; - left: 11px; + padding: 0; + margin: 0; } ul.popupmenu li { list-style-type: none; + display: inline-block; text-align: left; + width: 100%; } ul.popupmenu li:hover { @@ -43,30 +26,15 @@ ul.popupmenu li a { font-size: 9pt; } -ul.popupmenu li a i.icon-kick { - font-size: 8pt; +ul.popupmenu li i { + width: 15px; } -ul.popupmenu li a span { - display: inline-block; - width: 20px; - height: 16px; - text-align: center; +ul.popupmenu li span { + padding-left: 5px; } -span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover { - display:block !important; -} - -a.disabled { +ul.popupmenu a.disabled { color: gray !important; pointer-events: none; } - -.popupmenuPadding { - height: 35px; - width: 100px; - position: absolute; - bottom: -35; - left: 0px; -} \ No newline at end of file diff --git a/modules/UI/util/JitsiPopover.js b/modules/UI/util/JitsiPopover.js index f99d57747..5e278cb26 100644 --- a/modules/UI/util/JitsiPopover.js +++ b/modules/UI/util/JitsiPopover.js @@ -10,15 +10,26 @@ var JitsiPopover = (function () { { this.options = { skin: "white", - content: "" + content: "", + onClick: function () {}, + onShow: function () {} }; - if(options) - { - if(options.skin) + if (options) { + if (options.skin) { this.options.skin = options.skin; + } - if(options.content) + if (options.content) { this.options.content = options.content; + } + + if (options.onClick) { + this.options.onClick = options.onClick; + } + + if (options.onShow) { + this.options.onShow = options.onShow; + } } this.elementIsHovered = false; @@ -76,7 +87,10 @@ var JitsiPopover = (function () { */ JitsiPopover.prototype.createPopover = function () { $("body").append(this.template); - $(".jitsipopover > .jitsipopover-content").html(this.options.content); + $(".jitsipopover > .jitsipopover-content") + .html(this.options.content) + .click(this.options.onClick); + this.options.onShow(); var self = this; $(".jitsipopover").on("mouseenter", function () { self.popoverIsHovered = true; @@ -126,4 +140,4 @@ var JitsiPopover = (function () { return JitsiPopover; })(); -module.exports = JitsiPopover; \ No newline at end of file +module.exports = JitsiPopover; diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js index 60c9fbcf9..a16f49b6d 100644 --- a/modules/UI/videolayout/RemoteVideo.js +++ b/modules/UI/videolayout/RemoteVideo.js @@ -6,6 +6,7 @@ import SmallVideo from "./SmallVideo"; import AudioLevels from "../audio_levels/AudioLevels"; import UIUtils from "../util/UIUtil"; import UIEvents from '../../../service/UI/UIEvents'; +import JitsiPopover from "../util/JitsiPopover"; function RemoteVideo(id, VideoLayout, emitter) { this.id = id; @@ -18,6 +19,7 @@ function RemoteVideo(id, VideoLayout, emitter) { this.bindHoverHandler(); this.flipX = false; this.isLocal = false; + this.popover = null; } RemoteVideo.prototype = Object.create(SmallVideo.prototype); @@ -35,100 +37,89 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() { }; /** - * Adds the remote video menu element for the given id in the - * given parentElement. - * - * @param id the id indicating the video for which we're adding a menu. - * @param parentElement the parent element where this menu will be added + * Adds menu to the this remote video element. */ -if (!interfaceConfig.filmStripOnly) { - RemoteVideo.prototype.addRemoteVideoMenu = function () { - var spanElement = document.createElement('span'); - spanElement.className = 'remotevideomenu'; +RemoteVideo.prototype.addRemoteVideoMenu = function() { + if (interfaceConfig.filmStripOnly || this.popover) { + return; + } - this.container.appendChild(spanElement); - - var menuElement = document.createElement('i'); - menuElement.className = 'fa fa-angle-down'; - menuElement.title = 'Remote user controls'; - spanElement.appendChild(menuElement); - - - var popupmenuElement = document.createElement('ul'); - popupmenuElement.className = 'popupmenu'; - popupmenuElement.id = `remote_popupmenu_${this.id}`; - spanElement.appendChild(popupmenuElement); - - var muteMenuItem = document.createElement('li'); - var muteLinkItem = document.createElement('a'); - - var mutedIndicator = ""; - - if (!this.isMuted) { - muteLinkItem.innerHTML = mutedIndicator + - "
"; - muteLinkItem.className = 'mutelink'; - } - else { - muteLinkItem.innerHTML = mutedIndicator + - "
"; - muteLinkItem.className = 'mutelink disabled'; + let $popup = $( + ` + + ` + ); + $(this.container).append($popup); + this.popover = new JitsiPopover($popup, { + skin: 'black', + onClick: this.onRemoteVideoMenuClicked.bind(this), + onShow: () => { + $(`#${this.getRemoteMenuId()} [data-i18n]`).each(function (i, el) { + APP.translation.translateElement($(el)); + }); } + }); + this.updatePopover(); +}; - muteLinkItem.onclick = (event) => { - if ($(this).attr('disabled')) { - event.preventDefault(); - } - var isMute = !!this.isMuted; - this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id); +/** + * Get id of menu element for this remote video element. + * @returns {string} remote menu element id + */ +RemoteVideo.prototype.getRemoteMenuId = function () { + return `remote_popupmenu_${this.id}`; +}; - popupmenuElement.setAttribute('style', 'display:none;'); +/** + * Generate menu html for this remote video. + * @returns {string} remote menu html + */ +RemoteVideo.prototype.generateRemoteVideoMenu = function () { + let muteLabeli18n = + this.isMuted + ? 'videothumbnail.muted' + : 'videothumbnail.domute'; + return ` + + `; +}; - if (isMute) { - this.innerHTML = mutedIndicator + - "
"; - this.className = 'mutelink disabled'; - } - else { - this.innerHTML = mutedIndicator + - "
"; - this.className = 'mutelink'; - } - }; +/** + * Update remote menu. + */ +RemoteVideo.prototype.updatePopover = function () { + this.popover.updateContent(this.generateRemoteVideoMenu()); +}; - muteMenuItem.appendChild(muteLinkItem); - popupmenuElement.appendChild(muteMenuItem); +/** + * Click handler for the remote menu. + */ +RemoteVideo.prototype.onRemoteVideoMenuClicked = function (e) { + e.preventDefault(); - var ejectIndicator = ""; + let $target = $(e.target); - var ejectMenuItem = document.createElement('li'); - var ejectLinkItem = document.createElement('a'); - var ejectText = "
 
"; - ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText; - ejectLinkItem.onclick = (event) => { - this.emitter.emit(UIEvents.USER_KICKED, this.id); - popupmenuElement.setAttribute('style', 'display:none;'); - }; + if ($target.parents('.popupmenu-mute').length) { + this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id); + } else if ($target.parents('.popupmenu-kick').length) { + this.emitter.emit(UIEvents.USER_KICKED, this.id); + } - ejectMenuItem.appendChild(ejectLinkItem); - popupmenuElement.appendChild(ejectMenuItem); - - var paddingSpan = document.createElement('span'); - paddingSpan.className = 'popupmenuPadding'; - popupmenuElement.appendChild(paddingSpan); - APP.translation.translateElement( - $("#" + popupmenuElement.id + " > li > a > div")); - }; - -} else { - RemoteVideo.prototype.addRemoteVideoMenu = function() {}; -} + this.popover.forceHide(); +}; /** * Removes the remote stream element corresponding to the given stream and @@ -166,6 +157,11 @@ RemoteVideo.prototype.removeRemoteStreamElement = function (stream) { RemoteVideo.prototype.remove = function () { console.log("Remove thumbnail", this.id); this.removeConnectionIndicator(); + + if (this.popover) { + this.popover.forceHide(); + } + // Make sure that the large video is updated if are removing its // corresponding small video. this.VideoLayout.updateRemovedVideo(this.id); @@ -218,10 +214,7 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) { let onClickHandler = (event) => { let source = event.target || event.srcElement; - // ignore click if it was done in popup menu - if ($(source).parents('.popupmenu').length === 0) { - this.VideoLayout.handleVideoThumbClicked(false, this.id); - } + this.VideoLayout.handleVideoThumbClicked(false, this.id); // On IE we need to populate this handler on video // and it does not give event instance as an argument, @@ -317,26 +310,11 @@ RemoteVideo.prototype.hideConnectionIndicator = function () { /** * Updates the remote video menu. * - * @param id the id indicating the video for which we're adding a menu. * @param isMuted indicates the current mute state */ RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) { - var muteMenuItem = $(`#remote_popupmenu_${this.id}>li>a.mutelink`); - - var mutedIndicator = ""; - - if (muteMenuItem.length) { - var muteLink = muteMenuItem.get(0); - - if (isMuted) { - muteLink.innerHTML = mutedIndicator + ' Muted'; - muteLink.className = 'mutelink disabled'; - } - else { - muteLink.innerHTML = mutedIndicator + ' Mute'; - muteLink.className = 'mutelink'; - } - } + this.isMuted = isMuted; + this.updatePopover(); }; /** diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 22e6e16ef..ae6eeb5fd 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -399,9 +399,7 @@ var VideoLayout = { remoteVideos[id].createModeratorIndicatorElement(); } else if (isModerator) { // We are moderator, but user is not - add menu - if ($(`#remote_popupmenu_${id}`).length <= 0) { - remoteVideos[id].addRemoteVideoMenu(); - } + remoteVideos[id].addRemoteVideoMenu(); } }); },