|
@@ -6,6 +6,7 @@ import SmallVideo from "./SmallVideo";
|
6
|
6
|
import AudioLevels from "../audio_levels/AudioLevels";
|
7
|
7
|
import UIUtils from "../util/UIUtil";
|
8
|
8
|
import UIEvents from '../../../service/UI/UIEvents';
|
|
9
|
+import JitsiPopover from "../util/JitsiPopover";
|
9
|
10
|
|
10
|
11
|
function RemoteVideo(id, VideoLayout, emitter) {
|
11
|
12
|
this.id = id;
|
|
@@ -18,6 +19,7 @@ function RemoteVideo(id, VideoLayout, emitter) {
|
18
|
19
|
this.bindHoverHandler();
|
19
|
20
|
this.flipX = false;
|
20
|
21
|
this.isLocal = false;
|
|
22
|
+ this.isMuted = false;
|
21
|
23
|
}
|
22
|
24
|
|
23
|
25
|
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
|
|
@@ -34,6 +36,126 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
|
34
|
36
|
return this.container;
|
35
|
37
|
};
|
36
|
38
|
|
|
39
|
+
|
|
40
|
+/**
|
|
41
|
+ * Initializes the remote participant popup menu, by specifying previously
|
|
42
|
+ * constructed popupMenuElement, containing all the menu items.
|
|
43
|
+ *
|
|
44
|
+ * @param popupMenuElement a pre-constructed element, containing the menu items
|
|
45
|
+ * to display in the popup
|
|
46
|
+ */
|
|
47
|
+RemoteVideo.prototype._initPopupMenu = function (popupMenuElement) {
|
|
48
|
+ this.popover = new JitsiPopover(
|
|
49
|
+ $("#" + this.videoSpanId + " > .remotevideomenu"),
|
|
50
|
+ { content: popupMenuElement.outerHTML,
|
|
51
|
+ skin: "black"});
|
|
52
|
+
|
|
53
|
+ // override popover show method to make sure we will update the content
|
|
54
|
+ // before showing the popover
|
|
55
|
+ var origShowFunc = this.popover.show;
|
|
56
|
+ this.popover.show = function () {
|
|
57
|
+ // update content by forcing it, to finish even if popover
|
|
58
|
+ // is not visible
|
|
59
|
+ this.updateRemoteVideoMenu(this.isMuted, true);
|
|
60
|
+ // call the original show, passing its actual this
|
|
61
|
+ origShowFunc.call(this.popover);
|
|
62
|
+ }.bind(this);
|
|
63
|
+};
|
|
64
|
+
|
|
65
|
+/**
|
|
66
|
+ * Generates the popup menu content.
|
|
67
|
+ *
|
|
68
|
+ * @returns {Element|*} the constructed element, containing popup menu items
|
|
69
|
+ * @private
|
|
70
|
+ */
|
|
71
|
+RemoteVideo.prototype._generatePopupContent = function () {
|
|
72
|
+ var popupmenuElement = document.createElement('ul');
|
|
73
|
+ popupmenuElement.className = 'popupmenu';
|
|
74
|
+ popupmenuElement.id = `remote_popupmenu_${this.id}`;
|
|
75
|
+
|
|
76
|
+ var muteMenuItem = document.createElement('li');
|
|
77
|
+ var muteLinkItem = document.createElement('a');
|
|
78
|
+
|
|
79
|
+ var mutedIndicator = "<i class='icon-mic-disabled'></i>";
|
|
80
|
+
|
|
81
|
+ var doMuteHTML = mutedIndicator +
|
|
82
|
+ " <div " +
|
|
83
|
+ "data-i18n='videothumbnail.domute'>" +
|
|
84
|
+ APP.translation.translateString("videothumbnail.domute") +
|
|
85
|
+ "</div>";
|
|
86
|
+
|
|
87
|
+ var mutedHTML = mutedIndicator +
|
|
88
|
+ " <div " +
|
|
89
|
+ "data-i18n='videothumbnail.muted'>" +
|
|
90
|
+ APP.translation.translateString("videothumbnail.muted") +
|
|
91
|
+ "</div>";
|
|
92
|
+
|
|
93
|
+ muteLinkItem.id = "muteLinkItem";
|
|
94
|
+
|
|
95
|
+ if (this.isMuted) {
|
|
96
|
+ muteLinkItem.innerHTML = mutedHTML;
|
|
97
|
+ muteLinkItem.className = 'mutelink disabled';
|
|
98
|
+ }
|
|
99
|
+ else {
|
|
100
|
+ muteLinkItem.innerHTML = doMuteHTML;
|
|
101
|
+ muteLinkItem.className = 'mutelink';
|
|
102
|
+ }
|
|
103
|
+
|
|
104
|
+ // Delegate event to the document.
|
|
105
|
+ $(document).on("click", ".mutelink", function(){
|
|
106
|
+
|
|
107
|
+ if (this.isMuted)
|
|
108
|
+ return;
|
|
109
|
+
|
|
110
|
+ this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id);
|
|
111
|
+
|
|
112
|
+ this.popover.forceHide();
|
|
113
|
+ }.bind(this));
|
|
114
|
+
|
|
115
|
+ muteMenuItem.appendChild(muteLinkItem);
|
|
116
|
+ popupmenuElement.appendChild(muteMenuItem);
|
|
117
|
+
|
|
118
|
+ var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
|
|
119
|
+
|
|
120
|
+ var ejectMenuItem = document.createElement('li');
|
|
121
|
+ var ejectLinkItem = document.createElement('a');
|
|
122
|
+
|
|
123
|
+ var ejectText = "<div " +
|
|
124
|
+ "data-i18n='videothumbnail.kick'>" +
|
|
125
|
+ APP.translation.translateString("videothumbnail.kick") +
|
|
126
|
+ "</div>";
|
|
127
|
+
|
|
128
|
+ ejectLinkItem.className = 'ejectlink';
|
|
129
|
+ ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
|
|
130
|
+
|
|
131
|
+ $(document).on("click", ".ejectlink", function(){
|
|
132
|
+ this.emitter.emit(UIEvents.USER_KICKED, this.id);
|
|
133
|
+ this.popover.forceHide();
|
|
134
|
+ }.bind(this));
|
|
135
|
+
|
|
136
|
+ ejectMenuItem.appendChild(ejectLinkItem);
|
|
137
|
+ popupmenuElement.appendChild(ejectMenuItem);
|
|
138
|
+
|
|
139
|
+ return popupmenuElement;
|
|
140
|
+};
|
|
141
|
+
|
|
142
|
+/**
|
|
143
|
+ * Updates the remote video menu.
|
|
144
|
+ *
|
|
145
|
+ * @param isMuted the new muted state to update to
|
|
146
|
+ * @param force to work even if popover is not visible
|
|
147
|
+ */
|
|
148
|
+RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted, force) {
|
|
149
|
+
|
|
150
|
+ this.isMuted = isMuted;
|
|
151
|
+
|
|
152
|
+ // generate content, translate it and add it to document only if
|
|
153
|
+ // popover is visible or we force to do so.
|
|
154
|
+ if(this.popover.popoverShown || force) {
|
|
155
|
+ this.popover.updateContent(this._generatePopupContent());
|
|
156
|
+ }
|
|
157
|
+};
|
|
158
|
+
|
37
|
159
|
/**
|
38
|
160
|
* Adds the remote video menu element for the given <tt>id</tt> in the
|
39
|
161
|
* given <tt>parentElement</tt>.
|
|
@@ -43,9 +165,8 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
|
43
|
165
|
*/
|
44
|
166
|
if (!interfaceConfig.filmStripOnly) {
|
45
|
167
|
RemoteVideo.prototype.addRemoteVideoMenu = function () {
|
46
|
|
- var spanElement = document.createElement('span');
|
|
168
|
+ var spanElement = document.createElement('div');
|
47
|
169
|
spanElement.className = 'remotevideomenu';
|
48
|
|
-
|
49
|
170
|
this.container.appendChild(spanElement);
|
50
|
171
|
|
51
|
172
|
var menuElement = document.createElement('i');
|
|
@@ -53,77 +174,7 @@ if (!interfaceConfig.filmStripOnly) {
|
53
|
174
|
menuElement.title = 'Remote user controls';
|
54
|
175
|
spanElement.appendChild(menuElement);
|
55
|
176
|
|
56
|
|
-
|
57
|
|
- var popupmenuElement = document.createElement('ul');
|
58
|
|
- popupmenuElement.className = 'popupmenu';
|
59
|
|
- popupmenuElement.id = `remote_popupmenu_${this.id}`;
|
60
|
|
- spanElement.appendChild(popupmenuElement);
|
61
|
|
-
|
62
|
|
- var muteMenuItem = document.createElement('li');
|
63
|
|
- var muteLinkItem = document.createElement('a');
|
64
|
|
-
|
65
|
|
- var mutedIndicator = "<i style='float:left;' " +
|
66
|
|
- "class='icon-mic-disabled'></i>";
|
67
|
|
-
|
68
|
|
- if (!this.isMuted) {
|
69
|
|
- muteLinkItem.innerHTML = mutedIndicator +
|
70
|
|
- " <div style='width: 90px;margin-left: 20px;' " +
|
71
|
|
- "data-i18n='videothumbnail.domute'></div>";
|
72
|
|
- muteLinkItem.className = 'mutelink';
|
73
|
|
- }
|
74
|
|
- else {
|
75
|
|
- muteLinkItem.innerHTML = mutedIndicator +
|
76
|
|
- " <div style='width: 90px;margin-left: 20px;' " +
|
77
|
|
- "data-i18n='videothumbnail.muted'></div>";
|
78
|
|
- muteLinkItem.className = 'mutelink disabled';
|
79
|
|
- }
|
80
|
|
-
|
81
|
|
- muteLinkItem.onclick = (event) => {
|
82
|
|
- if ($(this).attr('disabled')) {
|
83
|
|
- event.preventDefault();
|
84
|
|
- }
|
85
|
|
- var isMute = !!this.isMuted;
|
86
|
|
- this.emitter.emit(UIEvents.REMOTE_AUDIO_MUTED, this.id);
|
87
|
|
-
|
88
|
|
- popupmenuElement.setAttribute('style', 'display:none;');
|
89
|
|
-
|
90
|
|
- if (isMute) {
|
91
|
|
- this.innerHTML = mutedIndicator +
|
92
|
|
- " <div style='width: 90px;margin-left: 20px;' " +
|
93
|
|
- "data-i18n='videothumbnail.muted'></div>";
|
94
|
|
- this.className = 'mutelink disabled';
|
95
|
|
- }
|
96
|
|
- else {
|
97
|
|
- this.innerHTML = mutedIndicator +
|
98
|
|
- " <div style='width: 90px;margin-left: 20px;' " +
|
99
|
|
- "data-i18n='videothumbnail.domute'></div>";
|
100
|
|
- this.className = 'mutelink';
|
101
|
|
- }
|
102
|
|
- };
|
103
|
|
-
|
104
|
|
- muteMenuItem.appendChild(muteLinkItem);
|
105
|
|
- popupmenuElement.appendChild(muteMenuItem);
|
106
|
|
-
|
107
|
|
- var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
|
108
|
|
-
|
109
|
|
- var ejectMenuItem = document.createElement('li');
|
110
|
|
- var ejectLinkItem = document.createElement('a');
|
111
|
|
- var ejectText = "<div style='width: 90px;margin-left: 20px;' " +
|
112
|
|
- "data-i18n='videothumbnail.kick'> </div>";
|
113
|
|
- ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
|
114
|
|
- ejectLinkItem.onclick = (event) => {
|
115
|
|
- this.emitter.emit(UIEvents.USER_KICKED, this.id);
|
116
|
|
- popupmenuElement.setAttribute('style', 'display:none;');
|
117
|
|
- };
|
118
|
|
-
|
119
|
|
- ejectMenuItem.appendChild(ejectLinkItem);
|
120
|
|
- popupmenuElement.appendChild(ejectMenuItem);
|
121
|
|
-
|
122
|
|
- var paddingSpan = document.createElement('span');
|
123
|
|
- paddingSpan.className = 'popupmenuPadding';
|
124
|
|
- popupmenuElement.appendChild(paddingSpan);
|
125
|
|
- APP.translation.translateElement(
|
126
|
|
- $("#" + popupmenuElement.id + " > li > a > div"));
|
|
177
|
+ this._initPopupMenu(this._generatePopupContent());
|
127
|
178
|
};
|
128
|
179
|
|
129
|
180
|
} else {
|
|
@@ -313,31 +364,6 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
|
313
|
364
|
this.connectionIndicator.hide();
|
314
|
365
|
};
|
315
|
366
|
|
316
|
|
-/**
|
317
|
|
- * Updates the remote video menu.
|
318
|
|
- *
|
319
|
|
- * @param id the id indicating the video for which we're adding a menu.
|
320
|
|
- * @param isMuted indicates the current mute state
|
321
|
|
- */
|
322
|
|
-RemoteVideo.prototype.updateRemoteVideoMenu = function (isMuted) {
|
323
|
|
- var muteMenuItem = $(`#remote_popupmenu_${this.id}>li>a.mutelink`);
|
324
|
|
-
|
325
|
|
- var mutedIndicator = "<i class='icon-mic-disabled'></i>";
|
326
|
|
-
|
327
|
|
- if (muteMenuItem.length) {
|
328
|
|
- var muteLink = muteMenuItem.get(0);
|
329
|
|
-
|
330
|
|
- if (isMuted) {
|
331
|
|
- muteLink.innerHTML = mutedIndicator + ' Muted';
|
332
|
|
- muteLink.className = 'mutelink disabled';
|
333
|
|
- }
|
334
|
|
- else {
|
335
|
|
- muteLink.innerHTML = mutedIndicator + ' Mute';
|
336
|
|
- muteLink.className = 'mutelink';
|
337
|
|
- }
|
338
|
|
- }
|
339
|
|
-};
|
340
|
|
-
|
341
|
367
|
/**
|
342
|
368
|
* Sets the display name for the given video span id.
|
343
|
369
|
*/
|
|
@@ -388,6 +414,7 @@ RemoteVideo.prototype.setDisplayName = function(displayName, key) {
|
388
|
414
|
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
389
|
415
|
var menuSpan = $('#' + this.videoSpanId + '>span.remotevideomenu');
|
390
|
416
|
if (menuSpan.length) {
|
|
417
|
+ this.popover.forceHide();
|
391
|
418
|
menuSpan.remove();
|
392
|
419
|
}
|
393
|
420
|
};
|