diff --git a/css/jitsi_popover.css b/css/jitsi_popover.css
index bdf8a09a9c..5936c87b26 100644
--- a/css/jitsi_popover.css
+++ b/css/jitsi_popover.css
@@ -71,7 +71,7 @@
height: 35px;
width: 100px;
position: absolute;
- bottom: -35;
+ bottom: -35px;
}
.jitsipopover_green
diff --git a/css/popup_menu.css b/css/popup_menu.css
index 041e04229b..90c9dc752e 100644
--- a/css/popup_menu.css
+++ b/css/popup_menu.css
@@ -1,27 +1,10 @@
/*Initialize*/
ul.popupmenu {
- display:none;
- position: absolute;
- padding:10px;
+ padding: 0px 10px 0px 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:3px;
-}
-
-ul.popupmenu:after {
- content: url('../images/popupPointer.png');
- display: block;
- position: absolute;
- bottom: -8px;
- left: 11px;
+ height: auto;
}
ul.popupmenu li {
@@ -36,11 +19,13 @@ ul.popupmenu li:hover {
/*Link Appearance*/
ul.popupmenu li a {
+ display: block;
text-decoration: none;
color: #fff;
padding: 5px;
- display: inline-block;
font-size: 9pt;
+ width: 100%;
+ cursor: hand;
}
ul.popupmenu li a i.icon-kick {
@@ -54,6 +39,15 @@ ul.popupmenu li a span {
text-align: center;
}
+ul.popupmenu li a div {
+ display: inline-block;
+ line-height: 25px;
+}
+
+ul.popupmenu li a i {
+ line-height: 25px;
+}
+
span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
display:block !important;
}
@@ -61,12 +55,4 @@ span.remotevideomenu:hover ul.popupmenu, ul.popupmenu:hover {
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/css/videolayout_default.css b/css/videolayout_default.css
index 8e97dcf87d..5588f26a3b 100644
--- a/css/videolayout_default.css
+++ b/css/videolayout_default.css
@@ -144,8 +144,7 @@
}
#remoteVideos .videocontainer>span.focusindicator,
-#remoteVideos .videocontainer>span.remotevideomenu {
- display: inline-block;
+#remoteVideos .videocontainer>div.remotevideomenu {
position: absolute;
color: #FFFFFF;
top: 0;
@@ -159,6 +158,14 @@
text-align: center;
}
+#remoteVideos .videocontainer>span.focusindicator {
+ display: inline-block;
+}
+
+#remoteVideos .videocontainer>div.remotevideomenu {
+ display: block;
+}
+
.videocontainer>span.displayname,
.videocontainer>input.displayname {
display: none;
diff --git a/modules/UI/videolayout/RemoteVideo.js b/modules/UI/videolayout/RemoteVideo.js
index 1076890e3d..487c90cb02 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.isMuted = false;
}
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
@@ -34,6 +36,126 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
return this.container;
};
+
+/**
+ * Initializes the remote participant popup menu, by specifying previously
+ * constructed popupMenuElement, containing all the menu items.
+ *
+ * @param popupMenuElement a pre-constructed element, containing the menu items
+ * to display in the popup
+ */
+RemoteVideo.prototype._initPopupMenu = function (popupMenuElement) {
+ this.popover = new JitsiPopover(
+ $("#" + this.videoSpanId + " > .remotevideomenu"),
+ { content: popupMenuElement.outerHTML,
+ skin: "black"});
+
+ // override popover show method to make sure we will update the content
+ // before showing the popover
+ var origShowFunc = this.popover.show;
+ this.popover.show = function () {
+ // update content by forcing it, to finish even if popover
+ // is not visible
+ this.updateRemoteVideoMenu(this.isMuted, true);
+ // call the original show, passing its actual this
+ origShowFunc.call(this.popover);
+ }.bind(this);
+};
+
+/**
+ * Generates the popup menu content.
+ *
+ * @returns {Element|*} the constructed element, containing popup menu items
+ * @private
+ */
+RemoteVideo.prototype._generatePopupContent = function () {
+ var popupmenuElement = document.createElement('ul');
+ popupmenuElement.className = 'popupmenu';
+ popupmenuElement.id = `remote_popupmenu_${this.id}`;
+
+ var muteMenuItem = document.createElement('li');
+ var muteLinkItem = document.createElement('a');
+
+ var mutedIndicator = "";
+
+ var doMuteHTML = mutedIndicator +
+ "
" +
+ APP.translation.translateString("videothumbnail.domute") +
+ "
";
+
+ var mutedHTML = mutedIndicator +
+ " " +
+ APP.translation.translateString("videothumbnail.muted") +
+ "
";
+
+ muteLinkItem.id = "muteLinkItem";
+
+ if (this.isMuted) {
+ muteLinkItem.innerHTML = mutedHTML;
+ muteLinkItem.className = 'mutelink disabled';
+ }
+ else {
+ muteLinkItem.innerHTML = doMuteHTML;
+ muteLinkItem.className = 'mutelink';
+ }
+
+ // Delegate event to the document.
+ $(document).on("click", ".mutelink", function(){
+
+ if (this.isMuted)
+ return;
+
+ this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id);
+
+ this.popover.forceHide();
+ }.bind(this));
+
+ muteMenuItem.appendChild(muteLinkItem);
+ popupmenuElement.appendChild(muteMenuItem);
+
+ var ejectIndicator = "";
+
+ var ejectMenuItem = document.createElement('li');
+ var ejectLinkItem = document.createElement('a');
+
+ var ejectText = "" +
+ APP.translation.translateString("videothumbnail.kick") +
+ "
";
+
+ ejectLinkItem.className = 'ejectlink';
+ ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
+
+ $(document).on("click", ".ejectlink", function(){
+ this.emitter.emit(UIEvents.USER_KICKED, this.id);
+ this.popover.forceHide();
+ }.bind(this));
+
+ ejectMenuItem.appendChild(ejectLinkItem);
+ popupmenuElement.appendChild(ejectMenuItem);
+
+ return popupmenuElement;
+};
+
+/**
+ * Updates the remote video menu.
+ *
+ * @param isMuted the new muted state to update to
+ * @param force to work even if popover is not visible
+ */
+RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted, force) {
+
+ this.isMuted = isMuted;
+
+ // generate content, translate it and add it to document only if
+ // popover is visible or we force to do so.
+ if(this.popover.popoverShown || force) {
+ this.popover.updateContent(this._generatePopupContent());
+ }
+};
+
/**
* Adds the remote video menu element for the given id in the
* given parentElement.
@@ -43,9 +165,8 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
*/
if (!interfaceConfig.filmStripOnly) {
RemoteVideo.prototype.addRemoteVideoMenu = function () {
- var spanElement = document.createElement('span');
+ var spanElement = document.createElement('div');
spanElement.className = 'remotevideomenu';
-
this.container.appendChild(spanElement);
var menuElement = document.createElement('i');
@@ -53,77 +174,7 @@ if (!interfaceConfig.filmStripOnly) {
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';
- }
-
- muteLinkItem.onclick = (event) => {
- if ($(this).attr('disabled')) {
- event.preventDefault();
- }
- var isMute = !!this.isMuted;
- this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id);
-
- popupmenuElement.setAttribute('style', 'display:none;');
-
- if (isMute) {
- this.innerHTML = mutedIndicator +
- " ";
- this.className = 'mutelink disabled';
- }
- else {
- this.innerHTML = mutedIndicator +
- " ";
- this.className = 'mutelink';
- }
- };
-
- muteMenuItem.appendChild(muteLinkItem);
- popupmenuElement.appendChild(muteMenuItem);
-
- var ejectIndicator = "";
-
- 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;');
- };
-
- 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"));
+ this._initPopupMenu(this._generatePopupContent());
};
} else {
@@ -313,31 +364,6 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
this.connectionIndicator.hide();
};
-/**
- * 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';
- }
- }
-};
-
/**
* Sets the display name for the given video span id.
*/
@@ -388,6 +414,7 @@ RemoteVideo.prototype.setDisplayName = function(displayName, key) {
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
var menuSpan = $('#' + this.videoSpanId + '>span.remotevideomenu');
if (menuSpan.length) {
+ this.popover.forceHide();
menuSpan.remove();
}
};