Refactors VideoLayout.js.
This commit is contained in:
parent
38b180ad81
commit
6a492d96c2
|
@ -19,7 +19,7 @@
|
||||||
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
||||||
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
||||||
<script src="interface_config.js?v=5"></script>
|
<script src="interface_config.js?v=5"></script>
|
||||||
<script src="libs/app.bundle.js?v=88"></script>
|
<script src="libs/app.bundle.js?v=89"></script>
|
||||||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||||
<link rel="stylesheet" href="css/font.css?v=7"/>
|
<link rel="stylesheet" href="css/font.css?v=7"/>
|
||||||
<link rel="stylesheet" href="css/toastr.css?v=1">
|
<link rel="stylesheet" href="css/toastr.css?v=1">
|
||||||
|
|
4478
libs/app.bundle.js
4478
libs/app.bundle.js
File diff suppressed because it is too large
Load Diff
|
@ -36,7 +36,7 @@ var DataChannels =
|
||||||
// selections so that it can do adaptive simulcast,
|
// selections so that it can do adaptive simulcast,
|
||||||
// we want the notification to trigger even if userJid is undefined,
|
// we want the notification to trigger even if userJid is undefined,
|
||||||
// or null.
|
// or null.
|
||||||
var userJid = APP.UI.getLargeVideoState().userResourceJid;
|
var userJid = APP.UI.getLargeVideoJid();
|
||||||
// we want the notification to trigger even if userJid is undefined,
|
// we want the notification to trigger even if userJid is undefined,
|
||||||
// or null.
|
// or null.
|
||||||
onSelectedEndpointChanged(userJid);
|
onSelectedEndpointChanged(userJid);
|
||||||
|
|
|
@ -143,7 +143,7 @@ function registerListeners() {
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
|
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
|
||||||
UI.getLargeVideoState().userResourceJid);
|
UI.getLargeVideoJid());
|
||||||
});
|
});
|
||||||
APP.desktopsharing.addListener(function () {
|
APP.desktopsharing.addListener(function () {
|
||||||
ToolbarToggler.showDesktopSharingButton();
|
ToolbarToggler.showDesktopSharingButton();
|
||||||
|
@ -215,8 +215,6 @@ function registerListeners() {
|
||||||
break;
|
break;
|
||||||
case 'recvonly':
|
case 'recvonly':
|
||||||
el.hide();
|
el.hide();
|
||||||
// FIXME: Check if we have to change large video
|
|
||||||
//VideoLayout.updateLargeVideo(el);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,6 +263,11 @@ function setVideoMute(mute, options) {
|
||||||
options);
|
options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onResize()
|
||||||
|
{
|
||||||
|
Chat.resizeChat();
|
||||||
|
VideoLayout.resizeLargeVideoContainer();
|
||||||
|
}
|
||||||
|
|
||||||
function bindEvents()
|
function bindEvents()
|
||||||
{
|
{
|
||||||
|
@ -272,16 +275,9 @@ function bindEvents()
|
||||||
* Resizes and repositions videos in full screen mode.
|
* Resizes and repositions videos in full screen mode.
|
||||||
*/
|
*/
|
||||||
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
|
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
|
||||||
function () {
|
onResize);
|
||||||
VideoLayout.resizeLargeVideoContainer();
|
|
||||||
VideoLayout.positionLarge();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$(window).resize(function () {
|
$(window).resize(onResize);
|
||||||
VideoLayout.resizeLargeVideoContainer();
|
|
||||||
VideoLayout.positionLarge();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UI.start = function (init) {
|
UI.start = function (init) {
|
||||||
|
@ -322,7 +318,6 @@ UI.start = function (init) {
|
||||||
|
|
||||||
$("#welcome_page").hide();
|
$("#welcome_page").hide();
|
||||||
|
|
||||||
VideoLayout.resizeLargeVideoContainer();
|
|
||||||
$("#videospace").mousemove(function () {
|
$("#videospace").mousemove(function () {
|
||||||
return ToolbarToggler.showToolbar();
|
return ToolbarToggler.showToolbar();
|
||||||
});
|
});
|
||||||
|
@ -550,9 +545,8 @@ function onMucMemberJoined(jid, id, displayName) {
|
||||||
VideoLayout.ensurePeerContainerExists(jid,id);
|
VideoLayout.ensurePeerContainerExists(jid,id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMucPresenceStatus( jid, info) {
|
function onMucPresenceStatus(jid, info) {
|
||||||
VideoLayout.setPresenceStatus(
|
VideoLayout.setPresenceStatus(Strophe.getResourceFromJid(jid), info.status);
|
||||||
'participant_' + Strophe.getResourceFromJid(jid), info.status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMucRoleChanged(role, displayName) {
|
function onMucRoleChanged(role, displayName) {
|
||||||
|
@ -615,9 +609,9 @@ UI.inputDisplayNameHandler = function (value) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
UI.getLargeVideoState = function()
|
UI.getLargeVideoJid = function()
|
||||||
{
|
{
|
||||||
return VideoLayout.getLargeVideoState();
|
return VideoLayout.getLargeVideoJid();
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.generateRoomName = function() {
|
UI.generateRoomName = function() {
|
||||||
|
@ -656,9 +650,9 @@ UI.generateRoomName = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
UI.connectionIndicatorShowMore = function(id)
|
UI.connectionIndicatorShowMore = function(jid)
|
||||||
{
|
{
|
||||||
return VideoLayout.connectionIndicators[id].showMore();
|
return VideoLayout.showMore(jid);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.showLoginPopup = function(callback)
|
UI.showLoginPopup = function(callback)
|
||||||
|
|
|
@ -13,14 +13,13 @@ function setVisibility(selector, show) {
|
||||||
function isUserMuted(jid) {
|
function isUserMuted(jid) {
|
||||||
// XXX(gp) we may want to rename this method to something like
|
// XXX(gp) we may want to rename this method to something like
|
||||||
// isUserStreaming, for example.
|
// isUserStreaming, for example.
|
||||||
if (jid && jid != APP.xmpp.myJid()) {
|
if (jid != APP.xmpp.myJid()) {
|
||||||
var resource = Strophe.getResourceFromJid(jid);
|
var resource = Strophe.getResourceFromJid(jid);
|
||||||
if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
|
if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if(jid && jid == APP.xmpp.myJid())
|
|
||||||
{
|
{
|
||||||
var localVideo = APP.RTC.localVideo;
|
var localVideo = APP.RTC.localVideo;
|
||||||
return (!localVideo || localVideo.isMuted());
|
return (!localVideo || localVideo.isMuted());
|
||||||
|
@ -117,7 +116,7 @@ var Avatar = {
|
||||||
//if the user is the currently focused, the dominant speaker or if
|
//if the user is the currently focused, the dominant speaker or if
|
||||||
//there is no focused and no dominant speaker and the large video is
|
//there is no focused and no dominant speaker and the large video is
|
||||||
//currently shown
|
//currently shown
|
||||||
if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
|
if (activeSpeakerJid === jid && require("../videolayout/LargeVideo").isLargeVideoOnTop()) {
|
||||||
setVisibility($("#largeVideo"), !show);
|
setVisibility($("#largeVideo"), !show);
|
||||||
setVisibility($('#activeSpeaker'), show);
|
setVisibility($('#activeSpeaker'), show);
|
||||||
setVisibility(avatar, false);
|
setVisibility(avatar, false);
|
||||||
|
@ -137,10 +136,6 @@ var Avatar = {
|
||||||
* @param jid of the current active speaker
|
* @param jid of the current active speaker
|
||||||
*/
|
*/
|
||||||
updateActiveSpeakerAvatarSrc: function (jid) {
|
updateActiveSpeakerAvatarSrc: function (jid) {
|
||||||
if (!jid) {
|
|
||||||
jid = APP.xmpp.findJidFromResource(
|
|
||||||
require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
|
|
||||||
}
|
|
||||||
var avatar = $("#activeSpeakerAvatar")[0];
|
var avatar = $("#activeSpeakerAvatar")[0];
|
||||||
var url = getGravatarUrl(users[jid],
|
var url = getGravatarUrl(users[jid],
|
||||||
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
|
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
|
||||||
|
|
|
@ -165,10 +165,10 @@ function presentationAdded(event, jid, presUrl, currentSlide) {
|
||||||
+ Strophe.getResourceFromJid(jid)
|
+ Strophe.getResourceFromJid(jid)
|
||||||
+ '_' + presId;
|
+ '_' + presId;
|
||||||
|
|
||||||
// We explicitly don't specify the peer jid here, because we don't want
|
|
||||||
// this video to be dealt with as a peer related one (for example we
|
|
||||||
// don't want to show a mute/kick menu for this one, etc.).
|
|
||||||
VideoLayout.addRemoteVideoContainer(null, elementId);
|
VideoLayout.addPreziContainer(elementId);
|
||||||
VideoLayout.resizeThumbnails();
|
VideoLayout.resizeThumbnails();
|
||||||
|
|
||||||
var controlsEnabled = false;
|
var controlsEnabled = false;
|
||||||
|
|
|
@ -5,6 +5,7 @@ var SettingsMenu = require("./settings/SettingsMenu");
|
||||||
var VideoLayout = require("../videolayout/VideoLayout");
|
var VideoLayout = require("../videolayout/VideoLayout");
|
||||||
var ToolbarToggler = require("../toolbars/ToolbarToggler");
|
var ToolbarToggler = require("../toolbars/ToolbarToggler");
|
||||||
var UIUtil = require("../util/UIUtil");
|
var UIUtil = require("../util/UIUtil");
|
||||||
|
var LargeVideo = require("../videolayout/LargeVideo");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggler for the chat, contact list, settings menu, etc..
|
* Toggler for the chat, contact list, settings menu, etc..
|
||||||
|
@ -18,90 +19,6 @@ var PanelToggler = (function(my) {
|
||||||
'#settingsmenu': '#settingsButton'
|
'#settingsmenu': '#settingsButton'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Resizes the video area
|
|
||||||
* @param isClosing whether the side panel is going to be closed or is going to open / remain opened
|
|
||||||
* @param completeFunction a function to be called when the video space is resized
|
|
||||||
*/
|
|
||||||
var resizeVideoArea = function(isClosing, completeFunction) {
|
|
||||||
var videospace = $('#videospace');
|
|
||||||
|
|
||||||
var panelSize = isClosing ? [0, 0] : PanelToggler.getPanelSize();
|
|
||||||
var videospaceWidth = window.innerWidth - panelSize[0];
|
|
||||||
var videospaceHeight = window.innerHeight;
|
|
||||||
var videoSize
|
|
||||||
= VideoLayout.getVideoSize(null, null, videospaceWidth, videospaceHeight);
|
|
||||||
var videoWidth = videoSize[0];
|
|
||||||
var videoHeight = videoSize[1];
|
|
||||||
var videoPosition = VideoLayout.getVideoPosition(videoWidth,
|
|
||||||
videoHeight,
|
|
||||||
videospaceWidth,
|
|
||||||
videospaceHeight);
|
|
||||||
var horizontalIndent = videoPosition[0];
|
|
||||||
var verticalIndent = videoPosition[1];
|
|
||||||
|
|
||||||
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
|
|
||||||
var thumbnailsWidth = thumbnailSize[0];
|
|
||||||
var thumbnailsHeight = thumbnailSize[1];
|
|
||||||
//for chat
|
|
||||||
|
|
||||||
videospace.animate({
|
|
||||||
right: panelSize[0],
|
|
||||||
width: videospaceWidth,
|
|
||||||
height: videospaceHeight
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queue: false,
|
|
||||||
duration: 500,
|
|
||||||
complete: completeFunction
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#remoteVideos').animate({
|
|
||||||
height: thumbnailsHeight
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queue: false,
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#remoteVideos>span').animate({
|
|
||||||
height: thumbnailsHeight,
|
|
||||||
width: thumbnailsWidth
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queue: false,
|
|
||||||
duration: 500,
|
|
||||||
complete: function () {
|
|
||||||
$(document).trigger(
|
|
||||||
"remotevideo.resized",
|
|
||||||
[thumbnailsWidth,
|
|
||||||
thumbnailsHeight]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#largeVideoContainer').animate({
|
|
||||||
width: videospaceWidth,
|
|
||||||
height: videospaceHeight
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queue: false,
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#largeVideo').animate({
|
|
||||||
width: videoWidth,
|
|
||||||
height: videoHeight,
|
|
||||||
top: verticalIndent,
|
|
||||||
bottom: verticalIndent,
|
|
||||||
left: horizontalIndent,
|
|
||||||
right: horizontalIndent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
queue: false,
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the windows in the side panel
|
* Toggles the windows in the side panel
|
||||||
* @param object the window that should be shown
|
* @param object the window that should be shown
|
||||||
|
@ -135,7 +52,7 @@ var PanelToggler = (function(my) {
|
||||||
else {
|
else {
|
||||||
// Undock the toolbar when the chat is shown and if we're in a
|
// Undock the toolbar when the chat is shown and if we're in a
|
||||||
// video mode.
|
// video mode.
|
||||||
if (VideoLayout.isLargeVideoVisible()) {
|
if (LargeVideo.isLargeVideoVisible()) {
|
||||||
ToolbarToggler.dockToolbar(false);
|
ToolbarToggler.dockToolbar(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +97,7 @@ var PanelToggler = (function(my) {
|
||||||
$('#chatspace').trigger('shown');
|
$('#chatspace').trigger('shown');
|
||||||
};
|
};
|
||||||
|
|
||||||
resizeVideoArea(Chat.isVisible(), chatCompleteFunction);
|
VideoLayout.resizeVideoArea(!Chat.isVisible(), chatCompleteFunction);
|
||||||
|
|
||||||
toggle(Chat,
|
toggle(Chat,
|
||||||
'#chatspace',
|
'#chatspace',
|
||||||
|
@ -203,7 +120,7 @@ var PanelToggler = (function(my) {
|
||||||
my.toggleContactList = function () {
|
my.toggleContactList = function () {
|
||||||
var completeFunction = ContactList.isVisible() ?
|
var completeFunction = ContactList.isVisible() ?
|
||||||
function() {} : function () { $('#contactlist').trigger('shown');};
|
function() {} : function () { $('#contactlist').trigger('shown');};
|
||||||
resizeVideoArea(ContactList.isVisible(), completeFunction);
|
VideoLayout.resizeVideoArea(!ContactList.isVisible(), completeFunction);
|
||||||
|
|
||||||
toggle(ContactList,
|
toggle(ContactList,
|
||||||
'#contactlist',
|
'#contactlist',
|
||||||
|
@ -218,7 +135,7 @@ var PanelToggler = (function(my) {
|
||||||
* Opens / closes the settings menu
|
* Opens / closes the settings menu
|
||||||
*/
|
*/
|
||||||
my.toggleSettingsMenu = function() {
|
my.toggleSettingsMenu = function() {
|
||||||
resizeVideoArea(SettingsMenu.isVisible(), function (){});
|
VideoLayout.resizeVideoArea(!SettingsMenu.isVisible(), function (){});
|
||||||
toggle(SettingsMenu,
|
toggle(SettingsMenu,
|
||||||
'#settingsmenu',
|
'#settingsmenu',
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -5,10 +5,12 @@ module.exports = {
|
||||||
/**
|
/**
|
||||||
* Returns the available video width.
|
* Returns the available video width.
|
||||||
*/
|
*/
|
||||||
getAvailableVideoWidth: function () {
|
getAvailableVideoWidth: function (isVisible) {
|
||||||
var PanelToggler = require("../side_pannels/SidePanelToggler");
|
var PanelToggler = require("../side_pannels/SidePanelToggler");
|
||||||
|
if(typeof isVisible === "undefined" || isVisible === null)
|
||||||
|
isVisible = PanelToggler.isVisible();
|
||||||
var rightPanelWidth
|
var rightPanelWidth
|
||||||
= PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
|
= isVisible ? PanelToggler.getPanelSize()[0] : 0;
|
||||||
|
|
||||||
return window.innerWidth - rightPanelWidth;
|
return window.innerWidth - rightPanelWidth;
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@ var JitsiPopover = require("../util/JitsiPopover");
|
||||||
* @param videoContainer the video container associated with the indicator.
|
* @param videoContainer the video container associated with the indicator.
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ConnectionIndicator(videoContainer, jid, VideoLayout)
|
function ConnectionIndicator(videoContainer, jid)
|
||||||
{
|
{
|
||||||
this.videoContainer = videoContainer;
|
this.videoContainer = videoContainer;
|
||||||
this.bandwidth = null;
|
this.bandwidth = null;
|
||||||
|
@ -17,7 +17,6 @@ function ConnectionIndicator(videoContainer, jid, VideoLayout)
|
||||||
this.popover = null;
|
this.popover = null;
|
||||||
this.jid = jid;
|
this.jid = jid;
|
||||||
this.create();
|
this.create();
|
||||||
this.videoLayout = VideoLayout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -153,10 +152,10 @@ ConnectionIndicator.prototype.generateText = function () {
|
||||||
translate("connectionindicator.resolution") + "</span></td>" +
|
translate("connectionindicator.resolution") + "</span></td>" +
|
||||||
"<td>" + resolution + "</td></tr></table>";
|
"<td>" + resolution + "</td></tr></table>";
|
||||||
|
|
||||||
if(this.videoContainer.id == "localVideoContainer") {
|
if(this.videoContainer.videoSpanId == "localVideoContainer") {
|
||||||
result += "<div class=\"jitsipopover_showmore\" " +
|
result += "<div class=\"jitsipopover_showmore\" " +
|
||||||
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
|
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
|
||||||
this.videoContainer.id + "')\" data-i18n='connectionindicator." +
|
this.jid + "')\" data-i18n='connectionindicator." +
|
||||||
(this.showMoreValue ? "less" : "more") + "'>" +
|
(this.showMoreValue ? "less" : "more") + "'>" +
|
||||||
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
|
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
|
||||||
"</div><br />";
|
"</div><br />";
|
||||||
|
@ -318,9 +317,9 @@ ConnectionIndicator.prototype.create = function () {
|
||||||
this.connectionIndicatorContainer = document.createElement("div");
|
this.connectionIndicatorContainer = document.createElement("div");
|
||||||
this.connectionIndicatorContainer.className = "connectionindicator";
|
this.connectionIndicatorContainer.className = "connectionindicator";
|
||||||
this.connectionIndicatorContainer.style.display = "none";
|
this.connectionIndicatorContainer.style.display = "none";
|
||||||
this.videoContainer.appendChild(this.connectionIndicatorContainer);
|
this.videoContainer.container.appendChild(this.connectionIndicatorContainer);
|
||||||
this.popover = new JitsiPopover(
|
this.popover = new JitsiPopover(
|
||||||
$("#" + this.videoContainer.id + " > .connectionindicator"),
|
$("#" + this.videoContainer.videoSpanId + " > .connectionindicator"),
|
||||||
{content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
|
{content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
|
||||||
APP.translation.translateString("connectionindicator.na") + "</div>",
|
APP.translation.translateString("connectionindicator.na") + "</div>",
|
||||||
skin: "black"});
|
skin: "black"});
|
||||||
|
@ -360,7 +359,7 @@ function (percent, object) {
|
||||||
{
|
{
|
||||||
if(this.connectionIndicatorContainer.style.display == "none") {
|
if(this.connectionIndicatorContainer.style.display == "none") {
|
||||||
this.connectionIndicatorContainer.style.display = "block";
|
this.connectionIndicatorContainer.style.display = "block";
|
||||||
this.videoLayout.updateMutePosition(this.videoContainer.id);
|
this.videoContainer.updateIconPositions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.bandwidth = object.bandwidth;
|
this.bandwidth = object.bandwidth;
|
||||||
|
|
|
@ -0,0 +1,420 @@
|
||||||
|
var Avatar = require("../avatar/Avatar");
|
||||||
|
var UIUtil = require("../util/UIUtil");
|
||||||
|
var UIEvents = require("../../../service/UI/UIEvents");
|
||||||
|
var xmpp = require("../../xmpp/xmpp");
|
||||||
|
|
||||||
|
var video = $('#largeVideo');
|
||||||
|
|
||||||
|
var currentVideoWidth = null;
|
||||||
|
var currentVideoHeight = null;
|
||||||
|
// By default we use camera
|
||||||
|
var getVideoSize = getCameraVideoSize;
|
||||||
|
var getVideoPosition = getCameraVideoPosition;
|
||||||
|
var currentSmallVideo = null;
|
||||||
|
var oldSmallVideo = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the size and position of the given video element.
|
||||||
|
*
|
||||||
|
* @param video the video element to position
|
||||||
|
* @param width the desired video width
|
||||||
|
* @param height the desired video height
|
||||||
|
* @param horizontalIndent the left and right indent
|
||||||
|
* @param verticalIndent the top and bottom indent
|
||||||
|
*/
|
||||||
|
function positionVideo(video,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
horizontalIndent,
|
||||||
|
verticalIndent,
|
||||||
|
animate) {
|
||||||
|
if(animate)
|
||||||
|
{
|
||||||
|
video.animate({
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
top: verticalIndent,
|
||||||
|
bottom: verticalIndent,
|
||||||
|
left: horizontalIndent,
|
||||||
|
right: horizontalIndent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queue: false,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
video.width(width);
|
||||||
|
video.height(height);
|
||||||
|
video.css({ top: verticalIndent + 'px',
|
||||||
|
bottom: verticalIndent + 'px',
|
||||||
|
left: horizontalIndent + 'px',
|
||||||
|
right: horizontalIndent + 'px'});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the video dimensions, so that it keeps it's aspect
|
||||||
|
* ratio and fits available area with it's larger dimension. This method
|
||||||
|
* ensures that whole video will be visible and can leave empty areas.
|
||||||
|
*
|
||||||
|
* @return an array with 2 elements, the video width and the video height
|
||||||
|
*/
|
||||||
|
function getDesktopVideoSize(videoWidth,
|
||||||
|
videoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight) {
|
||||||
|
if (!videoWidth)
|
||||||
|
videoWidth = currentVideoWidth;
|
||||||
|
if (!videoHeight)
|
||||||
|
videoHeight = currentVideoHeight;
|
||||||
|
|
||||||
|
var aspectRatio = videoWidth / videoHeight;
|
||||||
|
|
||||||
|
var availableWidth = Math.max(videoWidth, videoSpaceWidth);
|
||||||
|
var availableHeight = Math.max(videoHeight, videoSpaceHeight);
|
||||||
|
|
||||||
|
videoSpaceHeight -= $('#remoteVideos').outerHeight();
|
||||||
|
|
||||||
|
if (availableWidth / aspectRatio >= videoSpaceHeight)
|
||||||
|
{
|
||||||
|
availableHeight = videoSpaceHeight;
|
||||||
|
availableWidth = availableHeight * aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableHeight * aspectRatio >= videoSpaceWidth)
|
||||||
|
{
|
||||||
|
availableWidth = videoSpaceWidth;
|
||||||
|
availableHeight = availableWidth / aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [availableWidth, availableHeight];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the video horizontal and vertical indents,
|
||||||
|
* so that if fits its parent.
|
||||||
|
*
|
||||||
|
* @return an array with 2 elements, the horizontal indent and the vertical
|
||||||
|
* indent
|
||||||
|
*/
|
||||||
|
function getCameraVideoPosition(videoWidth,
|
||||||
|
videoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight) {
|
||||||
|
// Parent height isn't completely calculated when we position the video in
|
||||||
|
// full screen mode and this is why we use the screen height in this case.
|
||||||
|
// Need to think it further at some point and implement it properly.
|
||||||
|
var isFullScreen = document.fullScreen ||
|
||||||
|
document.mozFullScreen ||
|
||||||
|
document.webkitIsFullScreen;
|
||||||
|
if (isFullScreen)
|
||||||
|
videoSpaceHeight = window.innerHeight;
|
||||||
|
|
||||||
|
var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
||||||
|
var verticalIndent = (videoSpaceHeight - videoHeight) / 2;
|
||||||
|
|
||||||
|
return [horizontalIndent, verticalIndent];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the video horizontal and vertical indents.
|
||||||
|
* Centers horizontally and top aligns vertically.
|
||||||
|
*
|
||||||
|
* @return an array with 2 elements, the horizontal indent and the vertical
|
||||||
|
* indent
|
||||||
|
*/
|
||||||
|
function getDesktopVideoPosition(videoWidth,
|
||||||
|
videoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight) {
|
||||||
|
|
||||||
|
var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
||||||
|
|
||||||
|
var verticalIndent = 0;// Top aligned
|
||||||
|
|
||||||
|
return [horizontalIndent, verticalIndent];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the video dimensions, so that it covers the screen.
|
||||||
|
* It leaves no empty areas, but some parts of the video might not be visible.
|
||||||
|
*
|
||||||
|
* @return an array with 2 elements, the video width and the video height
|
||||||
|
*/
|
||||||
|
function getCameraVideoSize(videoWidth,
|
||||||
|
videoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight) {
|
||||||
|
if (!videoWidth)
|
||||||
|
videoWidth = currentVideoWidth;
|
||||||
|
if (!videoHeight)
|
||||||
|
videoHeight = currentVideoHeight;
|
||||||
|
|
||||||
|
var aspectRatio = videoWidth / videoHeight;
|
||||||
|
|
||||||
|
var availableWidth = Math.max(videoWidth, videoSpaceWidth);
|
||||||
|
var availableHeight = Math.max(videoHeight, videoSpaceHeight);
|
||||||
|
|
||||||
|
if (availableWidth / aspectRatio < videoSpaceHeight) {
|
||||||
|
availableHeight = videoSpaceHeight;
|
||||||
|
availableWidth = availableHeight * aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableHeight * aspectRatio < videoSpaceWidth) {
|
||||||
|
availableWidth = videoSpaceWidth;
|
||||||
|
availableHeight = availableWidth / aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [availableWidth, availableHeight];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function changeVideo(isVisible) {
|
||||||
|
Avatar.updateActiveSpeakerAvatarSrc(currentSmallVideo.peerJid);
|
||||||
|
|
||||||
|
APP.RTC.setVideoSrc($('#largeVideo')[0], currentSmallVideo.getSrc());
|
||||||
|
|
||||||
|
var videoTransform = document.getElementById('largeVideo')
|
||||||
|
.style.webkitTransform;
|
||||||
|
|
||||||
|
var flipX = currentSmallVideo.flipX;
|
||||||
|
|
||||||
|
if (flipX && videoTransform !== 'scaleX(-1)') {
|
||||||
|
document.getElementById('largeVideo').style.webkitTransform
|
||||||
|
= "scaleX(-1)";
|
||||||
|
}
|
||||||
|
else if (!flipX && videoTransform === 'scaleX(-1)') {
|
||||||
|
document.getElementById('largeVideo').style.webkitTransform
|
||||||
|
= "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
var isDesktop = APP.RTC.isVideoSrcDesktop(currentSmallVideo.peerJid);
|
||||||
|
// Change the way we'll be measuring and positioning large video
|
||||||
|
|
||||||
|
getVideoSize = isDesktop
|
||||||
|
? getDesktopVideoSize
|
||||||
|
: getCameraVideoSize;
|
||||||
|
getVideoPosition = isDesktop
|
||||||
|
? getDesktopVideoPosition
|
||||||
|
: getCameraVideoPosition;
|
||||||
|
|
||||||
|
|
||||||
|
// Only if the large video is currently visible.
|
||||||
|
// Disable previous dominant speaker video.
|
||||||
|
if (oldSmallVideo) {
|
||||||
|
oldSmallVideo.enableDominantSpeaker(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable new dominant speaker in the remote videos section.
|
||||||
|
if (currentSmallVideo) {
|
||||||
|
currentSmallVideo.enableDominantSpeaker(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVisible) {
|
||||||
|
// using "this" should be ok because we're called
|
||||||
|
// from within the fadeOut event.
|
||||||
|
$(this).fadeIn(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldSmallVideo)
|
||||||
|
Avatar.showUserAvatar(oldSmallVideo.peerJid);
|
||||||
|
}
|
||||||
|
|
||||||
|
var LargeVideo = {
|
||||||
|
|
||||||
|
init: function (VideoLayout, emitter) {
|
||||||
|
this.VideoLayout = VideoLayout;
|
||||||
|
this.eventEmitter = emitter;
|
||||||
|
var self = this;
|
||||||
|
// Listen for large video size updates
|
||||||
|
document.getElementById('largeVideo')
|
||||||
|
.addEventListener('loadedmetadata', function (e) {
|
||||||
|
currentVideoWidth = this.videoWidth;
|
||||||
|
currentVideoHeight = this.videoHeight;
|
||||||
|
self.position(currentVideoWidth, currentVideoHeight);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Indicates if the large video is currently visible.
|
||||||
|
*
|
||||||
|
* @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
|
||||||
|
*/
|
||||||
|
isLargeVideoVisible: function() {
|
||||||
|
return video.is(':visible');
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Updates the large video with the given new video source.
|
||||||
|
*/
|
||||||
|
updateLargeVideo: function(resourceJid, forceUpdate) {
|
||||||
|
console.log('hover in', resourceJid);
|
||||||
|
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
|
||||||
|
|
||||||
|
if ((currentSmallVideo && currentSmallVideo.resourceJid !== resourceJid)
|
||||||
|
|| forceUpdate) {
|
||||||
|
$('#activeSpeaker').css('visibility', 'hidden');
|
||||||
|
|
||||||
|
if(currentSmallVideo) {
|
||||||
|
oldSmallVideo = currentSmallVideo;
|
||||||
|
} else {
|
||||||
|
oldSmallVideo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSmallVideo = newSmallVideo;
|
||||||
|
var oldJid = null;
|
||||||
|
if(oldSmallVideo)
|
||||||
|
oldJid = oldSmallVideo.peerJid;
|
||||||
|
|
||||||
|
if (oldJid !== resourceJid) {
|
||||||
|
// we want the notification to trigger even if userJid is undefined,
|
||||||
|
// or null.
|
||||||
|
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
|
||||||
|
resourceJid);
|
||||||
|
}
|
||||||
|
|
||||||
|
video.fadeOut(300, changeVideo.bind(video, this.isLargeVideoVisible()));
|
||||||
|
} else {
|
||||||
|
var jid = null;
|
||||||
|
if(currentSmallVideo)
|
||||||
|
jid = currentSmallVideo.peerJid;
|
||||||
|
Avatar.showUserAvatar(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows/hides the large video.
|
||||||
|
*/
|
||||||
|
setLargeVideoVisible: function(isVisible) {
|
||||||
|
if (isVisible) {
|
||||||
|
$('#largeVideo').css({visibility: 'visible'});
|
||||||
|
$('.watermark').css({visibility: 'visible'});
|
||||||
|
if(currentSmallVideo)
|
||||||
|
currentSmallVideo.enableDominantSpeaker(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#largeVideo').css({visibility: 'hidden'});
|
||||||
|
$('#activeSpeaker').css('visibility', 'hidden');
|
||||||
|
$('.watermark').css({visibility: 'hidden'});
|
||||||
|
if(currentSmallVideo)
|
||||||
|
currentSmallVideo.enableDominantSpeaker(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onVideoTypeChanged: function (jid) {
|
||||||
|
if(jid && currentSmallVideo && jid === currentSmallVideo.peerJid)
|
||||||
|
{
|
||||||
|
var isDesktop = APP.RTC.isVideoSrcDesktop(jid);
|
||||||
|
getVideoSize = isDesktop
|
||||||
|
? getDesktopVideoSize
|
||||||
|
: getCameraVideoSize;
|
||||||
|
getVideoPosition = isDesktop
|
||||||
|
? getDesktopVideoPosition
|
||||||
|
: getCameraVideoPosition;
|
||||||
|
this.position(null, null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Positions the large video.
|
||||||
|
*
|
||||||
|
* @param videoWidth the stream video width
|
||||||
|
* @param videoHeight the stream video height
|
||||||
|
*/
|
||||||
|
position: function (videoWidth, videoHeight,
|
||||||
|
videoSpaceWidth, videoSpaceHeight, animate) {
|
||||||
|
if(!videoSpaceWidth)
|
||||||
|
videoSpaceWidth = $('#videospace').width();
|
||||||
|
if(!videoSpaceHeight)
|
||||||
|
videoSpaceHeight = window.innerHeight;
|
||||||
|
|
||||||
|
var videoSize = getVideoSize(videoWidth,
|
||||||
|
videoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight);
|
||||||
|
|
||||||
|
var largeVideoWidth = videoSize[0];
|
||||||
|
var largeVideoHeight = videoSize[1];
|
||||||
|
|
||||||
|
var videoPosition = getVideoPosition(largeVideoWidth,
|
||||||
|
largeVideoHeight,
|
||||||
|
videoSpaceWidth,
|
||||||
|
videoSpaceHeight);
|
||||||
|
|
||||||
|
var horizontalIndent = videoPosition[0];
|
||||||
|
var verticalIndent = videoPosition[1];
|
||||||
|
|
||||||
|
positionVideo($('#largeVideo'),
|
||||||
|
largeVideoWidth,
|
||||||
|
largeVideoHeight,
|
||||||
|
horizontalIndent, verticalIndent, animate);
|
||||||
|
},
|
||||||
|
|
||||||
|
isLargeVideoOnTop: function () {
|
||||||
|
var Etherpad = require("../etherpad/Etherpad");
|
||||||
|
var Prezi = require("../prezi/Prezi");
|
||||||
|
return !Prezi.isPresentationVisible() && !Etherpad.isVisible();
|
||||||
|
},
|
||||||
|
resize: function (animate, isVisible, completeFunction) {
|
||||||
|
var availableHeight = window.innerHeight;
|
||||||
|
var availableWidth = UIUtil.getAvailableVideoWidth(isVisible);
|
||||||
|
|
||||||
|
if (availableWidth < 0 || availableHeight < 0) return;
|
||||||
|
|
||||||
|
var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
|
||||||
|
var top = availableHeight / 2 - avatarSize / 4 * 3;
|
||||||
|
$('#activeSpeaker').css('top', top);
|
||||||
|
|
||||||
|
if(animate)
|
||||||
|
{
|
||||||
|
$('#videospace').animate({
|
||||||
|
right: window.innerWidth - availableWidth,
|
||||||
|
width: availableWidth,
|
||||||
|
height: availableHeight
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queue: false,
|
||||||
|
duration: 500,
|
||||||
|
complete: completeFunction
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#largeVideoContainer').animate({
|
||||||
|
width: availableWidth,
|
||||||
|
height: availableHeight
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queue: false,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$('#videospace').width(availableWidth);
|
||||||
|
$('#videospace').height(availableHeight);
|
||||||
|
$('#largeVideoContainer').width(availableWidth);
|
||||||
|
$('#largeVideoContainer').height(availableHeight);
|
||||||
|
}
|
||||||
|
return [availableWidth, availableHeight];
|
||||||
|
|
||||||
|
},
|
||||||
|
resizeVideoAreaAnimated: function (isVisible, completeFunction) {
|
||||||
|
var size = this.resize(true, isVisible, completeFunction);
|
||||||
|
this.position(null, null, size[0], size[1], true);
|
||||||
|
},
|
||||||
|
getResourceJid: function () {
|
||||||
|
if(!currentSmallVideo)
|
||||||
|
return null;
|
||||||
|
return currentSmallVideo.peerJid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = LargeVideo;
|
|
@ -0,0 +1,227 @@
|
||||||
|
var SmallVideo = require("./SmallVideo");
|
||||||
|
var ConnectionIndicator = require("./ConnectionIndicator");
|
||||||
|
var NicknameHandler = require("../util/NicknameHandler");
|
||||||
|
var UIUtil = require("../util/UIUtil");
|
||||||
|
var LargeVideo = require("./LargeVideo");
|
||||||
|
|
||||||
|
function LocalVideo(VideoLayout)
|
||||||
|
{
|
||||||
|
this.videoSpanId = "localVideoContainer";
|
||||||
|
this.container = $("#localVideoContainer").get(0);
|
||||||
|
this.VideoLayout = VideoLayout;
|
||||||
|
this.flipX = true;
|
||||||
|
this.peerJid = null;
|
||||||
|
this.resourceJid = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVideo.prototype = Object.create(SmallVideo.prototype);
|
||||||
|
LocalVideo.prototype.constructor = LocalVideo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the edit display name button.
|
||||||
|
*
|
||||||
|
* @returns the edit button
|
||||||
|
*/
|
||||||
|
function createEditDisplayNameButton() {
|
||||||
|
var editButton = document.createElement('a');
|
||||||
|
editButton.className = 'displayname';
|
||||||
|
UIUtil.setTooltip(editButton,
|
||||||
|
"videothumbnail.editnickname",
|
||||||
|
"top");
|
||||||
|
editButton.innerHTML = '<i class="fa fa-pencil"></i>';
|
||||||
|
|
||||||
|
return editButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the display name for the given video span id.
|
||||||
|
*/
|
||||||
|
LocalVideo.prototype.setDisplayName = function(displayName, key) {
|
||||||
|
|
||||||
|
if (!this.container) {
|
||||||
|
console.warn(
|
||||||
|
"Unable to set displayName - " + this.videoSpanId + " does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
|
||||||
|
var defaultLocalDisplayName = APP.translation.generateTranslatonHTML(
|
||||||
|
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
|
||||||
|
|
||||||
|
// If we already have a display name for this video.
|
||||||
|
if (nameSpan.length > 0) {
|
||||||
|
|
||||||
|
if (nameSpan.text() !== displayName) {
|
||||||
|
if (displayName && displayName.length > 0)
|
||||||
|
{
|
||||||
|
var meHTML = APP.translation.generateTranslatonHTML("me");
|
||||||
|
$('#localDisplayName').html(displayName + ' (' + meHTML + ')');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$('#localDisplayName').html(defaultLocalDisplayName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var editButton = createEditDisplayNameButton();
|
||||||
|
|
||||||
|
nameSpan = document.createElement('span');
|
||||||
|
nameSpan.className = 'displayname';
|
||||||
|
$('#' + this.videoSpanId)[0].appendChild(nameSpan);
|
||||||
|
|
||||||
|
|
||||||
|
if (displayName && displayName.length > 0) {
|
||||||
|
var meHTML = APP.translation.generateTranslatonHTML("me");
|
||||||
|
nameSpan.innerHTML = displayName + meHTML;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nameSpan.innerHTML = defaultLocalDisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nameSpan.id = 'localDisplayName';
|
||||||
|
this.container.appendChild(editButton);
|
||||||
|
//translates popover of edit button
|
||||||
|
APP.translation.translateElement($("a.displayname"));
|
||||||
|
|
||||||
|
var editableText = document.createElement('input');
|
||||||
|
editableText.className = 'displayname';
|
||||||
|
editableText.type = 'text';
|
||||||
|
editableText.id = 'editDisplayName';
|
||||||
|
|
||||||
|
if (displayName && displayName.length) {
|
||||||
|
editableText.value = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultNickname = APP.translation.translateString(
|
||||||
|
"defaultNickname", {name: "Jane Pink"});
|
||||||
|
editableText.setAttribute('style', 'display:none;');
|
||||||
|
editableText.setAttribute('data-18n',
|
||||||
|
'[placeholder]defaultNickname');
|
||||||
|
editableText.setAttribute("data-i18n-options",
|
||||||
|
JSON.stringify({name: "Jane Pink"}));
|
||||||
|
editableText.setAttribute("placeholder", defaultNickname);
|
||||||
|
|
||||||
|
this.container.appendChild(editableText);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
$('#localVideoContainer .displayname')
|
||||||
|
.bind("click", function (e) {
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
$('#localDisplayName').hide();
|
||||||
|
$('#editDisplayName').show();
|
||||||
|
$('#editDisplayName').focus();
|
||||||
|
$('#editDisplayName').select();
|
||||||
|
|
||||||
|
$('#editDisplayName').one("focusout", function (e) {
|
||||||
|
self.VideoLayout.inputDisplayNameHandler(this.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#editDisplayName').on('keydown', function (e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
e.preventDefault();
|
||||||
|
self.VideoLayout.inputDisplayNameHandler(this.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVideo.prototype.inputDisplayNameHandler = function (name) {
|
||||||
|
NicknameHandler.setNickname(name);
|
||||||
|
|
||||||
|
if (!$('#localDisplayName').is(":visible")) {
|
||||||
|
if (NicknameHandler.getNickname())
|
||||||
|
{
|
||||||
|
var meHTML = APP.translation.generateTranslatonHTML("me");
|
||||||
|
$('#localDisplayName').html(NicknameHandler.getNickname() + " (" + meHTML + ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var defaultHTML = APP.translation.generateTranslatonHTML(
|
||||||
|
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
|
||||||
|
$('#localDisplayName')
|
||||||
|
.html(defaultHTML);
|
||||||
|
}
|
||||||
|
$('#localDisplayName').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#editDisplayName').hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVideo.prototype.createConnectionIndicator = function()
|
||||||
|
{
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.connectionIndicator
|
||||||
|
= new ConnectionIndicator(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function localVideoClick(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
self.VideoLayout.handleVideoThumbClicked(
|
||||||
|
false,
|
||||||
|
APP.xmpp.myResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#localVideoContainer').click(localVideoClick);
|
||||||
|
|
||||||
|
// Add hover handler
|
||||||
|
$('#localVideoContainer').hover(
|
||||||
|
function() {
|
||||||
|
self.showDisplayName(true);
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
if (!LargeVideo.isLargeVideoVisible()
|
||||||
|
|| APP.xmpp.myResource() !== LargeVideo.getResourceJid())
|
||||||
|
self.showDisplayName(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if(isMuted)
|
||||||
|
{
|
||||||
|
APP.UI.setVideoMute(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.flipX = (stream.videoType == "screen")? false : true;
|
||||||
|
var localVideo = document.createElement('video');
|
||||||
|
localVideo.id = 'localVideo_' +
|
||||||
|
APP.RTC.getStreamID(stream.getOriginalStream());
|
||||||
|
localVideo.autoplay = true;
|
||||||
|
localVideo.volume = 0; // is it required if audio is separated ?
|
||||||
|
localVideo.oncontextmenu = function () { return false; };
|
||||||
|
|
||||||
|
var localVideoContainer = document.getElementById('localVideoWrapper');
|
||||||
|
localVideoContainer.appendChild(localVideo);
|
||||||
|
|
||||||
|
var localVideoSelector = $('#' + localVideo.id);
|
||||||
|
|
||||||
|
// Add click handler to both video and video wrapper elements in case
|
||||||
|
// there's no video.
|
||||||
|
localVideoSelector.click(localVideoClick);
|
||||||
|
|
||||||
|
if (this.flipX) {
|
||||||
|
localVideoSelector.addClass("flipVideoX");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach WebRTC stream
|
||||||
|
APP.RTC.attachMediaStream(localVideoSelector, stream.getOriginalStream());
|
||||||
|
|
||||||
|
// Add stream ended handler
|
||||||
|
stream.getOriginalStream().onended = function () {
|
||||||
|
localVideoContainer.removeChild(localVideo);
|
||||||
|
self.VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVideo.prototype.joined = function (jid) {
|
||||||
|
this.peerJid = jid;
|
||||||
|
this.resourceJid = Strophe.getResourceFromJid(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LocalVideo;
|
|
@ -0,0 +1,398 @@
|
||||||
|
var ConnectionIndicator = require("./ConnectionIndicator");
|
||||||
|
var SmallVideo = require("./SmallVideo");
|
||||||
|
var AudioLevels = require("../audio_levels/AudioLevels");
|
||||||
|
var LargeVideo = require("./LargeVideo");
|
||||||
|
var Avatar = require("../avatar/Avatar");
|
||||||
|
|
||||||
|
function RemoteVideo(peerJid, VideoLayout)
|
||||||
|
{
|
||||||
|
this.peerJid = peerJid;
|
||||||
|
this.resourceJid = Strophe.getResourceFromJid(peerJid);
|
||||||
|
this.videoSpanId = 'participant_' + this.resourceJid;
|
||||||
|
this.VideoLayout = VideoLayout;
|
||||||
|
this.addRemoteVideoContainer();
|
||||||
|
this.connectionIndicator = new ConnectionIndicator(
|
||||||
|
this, this.peerJid);
|
||||||
|
this.setDisplayName();
|
||||||
|
var nickfield = document.createElement('span');
|
||||||
|
nickfield.className = "nick";
|
||||||
|
nickfield.appendChild(document.createTextNode(this.resourceJid));
|
||||||
|
this.container.appendChild(nickfield);
|
||||||
|
this.flipX = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
|
||||||
|
RemoteVideo.prototype.constructor = RemoteVideo;
|
||||||
|
|
||||||
|
RemoteVideo.prototype.addRemoteVideoContainer = function() {
|
||||||
|
this.container = RemoteVideo.createContainer(this.videoSpanId);
|
||||||
|
if (APP.xmpp.isModerator())
|
||||||
|
this.addRemoteVideoMenu();
|
||||||
|
AudioLevels.updateAudioLevelCanvas(this.peerJid, this.VideoLayout);
|
||||||
|
|
||||||
|
return this.container;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the remote video menu element for the given <tt>jid</tt> in the
|
||||||
|
* given <tt>parentElement</tt>.
|
||||||
|
*
|
||||||
|
* @param jid the jid indicating the video for which we're adding a menu.
|
||||||
|
* @param parentElement the parent element where this menu will be added
|
||||||
|
*/
|
||||||
|
RemoteVideo.prototype.addRemoteVideoMenu = function () {
|
||||||
|
var spanElement = document.createElement('span');
|
||||||
|
spanElement.className = 'remotevideomenu';
|
||||||
|
|
||||||
|
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.resourceJid;
|
||||||
|
spanElement.appendChild(popupmenuElement);
|
||||||
|
|
||||||
|
var muteMenuItem = document.createElement('li');
|
||||||
|
var muteLinkItem = document.createElement('a');
|
||||||
|
|
||||||
|
var mutedIndicator = "<i style='float:left;' class='icon-mic-disabled'></i>";
|
||||||
|
|
||||||
|
if (!this.isMuted) {
|
||||||
|
muteLinkItem.innerHTML = mutedIndicator +
|
||||||
|
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
|
||||||
|
muteLinkItem.className = 'mutelink';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
muteLinkItem.innerHTML = mutedIndicator +
|
||||||
|
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
|
||||||
|
muteLinkItem.className = 'mutelink disabled';
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
muteLinkItem.onclick = function(){
|
||||||
|
if ($(this).attr('disabled') != undefined) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
var isMute = self.isMuted == true;
|
||||||
|
APP.xmpp.setMute(self.peerJid, !isMute);
|
||||||
|
|
||||||
|
popupmenuElement.setAttribute('style', 'display:none;');
|
||||||
|
|
||||||
|
if (isMute) {
|
||||||
|
this.innerHTML = mutedIndicator +
|
||||||
|
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
|
||||||
|
this.className = 'mutelink disabled';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.innerHTML = mutedIndicator +
|
||||||
|
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
|
||||||
|
this.className = 'mutelink';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
muteMenuItem.appendChild(muteLinkItem);
|
||||||
|
popupmenuElement.appendChild(muteMenuItem);
|
||||||
|
|
||||||
|
var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
|
||||||
|
|
||||||
|
var ejectMenuItem = document.createElement('li');
|
||||||
|
var ejectLinkItem = document.createElement('a');
|
||||||
|
var ejectText = "<div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.kick'> </div>";
|
||||||
|
ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
|
||||||
|
ejectLinkItem.onclick = function(){
|
||||||
|
APP.xmpp.eject(self.peerJid);
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the remote stream element corresponding to the given stream and
|
||||||
|
* parent container.
|
||||||
|
*
|
||||||
|
* @param stream the stream
|
||||||
|
* @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
RemoteVideo.prototype.removeRemoteStreamElement = function (stream, isVideo, id) {
|
||||||
|
if (!this.container)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var select = null;
|
||||||
|
var removedVideoSrc = null;
|
||||||
|
if (isVideo) {
|
||||||
|
select = $('#' + id);
|
||||||
|
removedVideoSrc = APP.RTC.getVideoSrc(select.get(0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
select = $('#' + this.videoSpanId + '>audio');
|
||||||
|
|
||||||
|
|
||||||
|
// Mark video as removed to cancel waiting loop(if video is removed
|
||||||
|
// before has started)
|
||||||
|
select.removed = true;
|
||||||
|
select.remove();
|
||||||
|
|
||||||
|
var audioCount = $('#' + this.videoSpanId + '>audio').length;
|
||||||
|
var videoCount = $('#' + this.videoSpanId + '>video').length;
|
||||||
|
|
||||||
|
if (!audioCount && !videoCount) {
|
||||||
|
console.log("Remove whole user", this.videoSpanId);
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.remove();
|
||||||
|
// Remove whole container
|
||||||
|
this.container.remove();
|
||||||
|
|
||||||
|
this.VideoLayout.resizeThumbnails();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removedVideoSrc)
|
||||||
|
this.VideoLayout.updateRemovedVideo(removedVideoSrc);
|
||||||
|
};
|
||||||
|
|
||||||
|
RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
|
||||||
|
var isVideo = stream.getVideoTracks().length > 0;
|
||||||
|
if(!this.container)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var streamElement = SmallVideo.createStreamElement(sid, stream);
|
||||||
|
var newElementId = streamElement.id;
|
||||||
|
|
||||||
|
this.container.appendChild(streamElement);
|
||||||
|
|
||||||
|
var sel = $('#' + newElementId);
|
||||||
|
sel.hide();
|
||||||
|
|
||||||
|
// If the container is currently visible we attach the stream.
|
||||||
|
if (!isVideo
|
||||||
|
|| (this.container.offsetParent !== null && isVideo)) {
|
||||||
|
APP.RTC.attachMediaStream(sel, stream);
|
||||||
|
|
||||||
|
if (isVideo)
|
||||||
|
this.waitForRemoteVideo(sel, thessrc, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
stream.onended = function () {
|
||||||
|
console.log('stream ended', this);
|
||||||
|
|
||||||
|
self.removeRemoteStreamElement(stream, isVideo, newElementId);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add click handler.
|
||||||
|
this.container.onclick = function (event) {
|
||||||
|
/*
|
||||||
|
* FIXME It turns out that videoThumb may not exist (if there is
|
||||||
|
* no actual video).
|
||||||
|
*/
|
||||||
|
var videoThumb = $('#' + self.videoSpanId + '>video').get(0);
|
||||||
|
if (videoThumb) {
|
||||||
|
self.VideoLayout.handleVideoThumbClicked(
|
||||||
|
false,
|
||||||
|
self.resourceJid);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
//FIXME
|
||||||
|
// Add hover handler
|
||||||
|
$(this.container).hover(
|
||||||
|
function() {
|
||||||
|
self.showDisplayName(true);
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
var videoSrc = null;
|
||||||
|
if ($('#' + self.videoSpanId + '>video')
|
||||||
|
&& $('#' + self.videoSpanId + '>video').length > 0) {
|
||||||
|
videoSrc = APP.RTC.getVideoSrc($('#' + self.videoSpanId + '>video').get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the video has been "pinned" by the user we want to
|
||||||
|
// keep the display name on place.
|
||||||
|
if (!LargeVideo.isLargeVideoVisible()
|
||||||
|
|| videoSrc !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
|
||||||
|
self.showDisplayName(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RemoteVideo.prototype.waitForRemoteVideo = function(selector, ssrc, stream) {
|
||||||
|
if (selector.removed || !selector.parent().is(":visible")) {
|
||||||
|
console.warn("Media removed before had started", selector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream.id === 'mixedmslabel') return;
|
||||||
|
|
||||||
|
if (selector[0].currentTime > 0) {
|
||||||
|
APP.RTC.attachMediaStream(selector, stream); // FIXME: why do i have to do this for FF?
|
||||||
|
this.VideoLayout.videoactive(selector, this.resourceJid);
|
||||||
|
} else {
|
||||||
|
var self = this;
|
||||||
|
setTimeout(function () {
|
||||||
|
self.waitForRemoteVideo(selector, ssrc, stream);
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show/hide peer container for the given resourceJid.
|
||||||
|
*/
|
||||||
|
RemoteVideo.prototype.showPeerContainer = function (state) {
|
||||||
|
if (!this.container)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var isHide = state === 'hide';
|
||||||
|
var resizeThumbnails = false;
|
||||||
|
|
||||||
|
if (!isHide) {
|
||||||
|
if (!$(this.container).is(':visible')) {
|
||||||
|
resizeThumbnails = true;
|
||||||
|
$(this.container).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
Avatar.showUserAvatar(this.peerJid, (state !== 'show'));
|
||||||
|
}
|
||||||
|
else if ($(this.container).is(':visible') && isHide)
|
||||||
|
{
|
||||||
|
resizeThumbnails = true;
|
||||||
|
$(this.container).hide();
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizeThumbnails) {
|
||||||
|
this.VideoLayout.resizeThumbnails();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to be able to pin a participant from the contact list, even
|
||||||
|
// if he's not in the lastN set!
|
||||||
|
// ContactList.setClickable(resourceJid, !isHide);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
RemoteVideo.prototype.removeConnectionIndicator = function () {
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteVideo.prototype.hideConnectionIndicator = function () {
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the remote video menu.
|
||||||
|
*
|
||||||
|
* @param jid the jid 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.resourceJid
|
||||||
|
+ '>li>a.mutelink');
|
||||||
|
|
||||||
|
var mutedIndicator = "<i class='icon-mic-disabled'></i>";
|
||||||
|
|
||||||
|
if (muteMenuItem.length) {
|
||||||
|
var muteLink = muteMenuItem.get(0);
|
||||||
|
|
||||||
|
if (isMuted === 'true') {
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
RemoteVideo.prototype.setDisplayName = function(displayName, key) {
|
||||||
|
|
||||||
|
if (!this.container) {
|
||||||
|
console.warn(
|
||||||
|
"Unable to set displayName - " + this.videoSpanId + " does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
|
||||||
|
|
||||||
|
// If we already have a display name for this video.
|
||||||
|
if (nameSpan.length > 0) {
|
||||||
|
if (displayName && displayName.length > 0)
|
||||||
|
{
|
||||||
|
$('#' + this.videoSpanId + '_name').html(displayName);
|
||||||
|
}
|
||||||
|
else if (key && key.length > 0)
|
||||||
|
{
|
||||||
|
var nameHtml = APP.translation.generateTranslatonHTML(key);
|
||||||
|
$('#' + this.videoSpanId + '_name').html(nameHtml);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$('#' + this.videoSpanId + '_name').text(
|
||||||
|
interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
|
||||||
|
} else {
|
||||||
|
nameSpan = document.createElement('span');
|
||||||
|
nameSpan.className = 'displayname';
|
||||||
|
$('#' + this.videoSpanId)[0].appendChild(nameSpan);
|
||||||
|
|
||||||
|
|
||||||
|
if (displayName && displayName.length > 0) {
|
||||||
|
|
||||||
|
nameSpan.innerText = displayName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
|
||||||
|
|
||||||
|
|
||||||
|
nameSpan.id = this.videoSpanId + '_name';
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes remote video menu element from video element identified by
|
||||||
|
* given <tt>videoElementId</tt>.
|
||||||
|
*
|
||||||
|
* @param videoElementId the id of local or remote video element.
|
||||||
|
*/
|
||||||
|
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
||||||
|
var menuSpan = $('#' + this.videoSpanId + '>span.remotevideomenu');
|
||||||
|
if (menuSpan.length) {
|
||||||
|
menuSpan.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteVideo.createContainer = function (spanId) {
|
||||||
|
var container = document.createElement('span');
|
||||||
|
container.id = spanId;
|
||||||
|
container.className = 'videocontainer';
|
||||||
|
var remotes = document.getElementById('remoteVideos');
|
||||||
|
return remotes.appendChild(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = RemoteVideo;
|
|
@ -0,0 +1,285 @@
|
||||||
|
var UIUtil = require("../util/UIUtil");
|
||||||
|
var LargeVideo = require("./LargeVideo");
|
||||||
|
|
||||||
|
function SmallVideo(){
|
||||||
|
this.isMuted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVideo.prototype.showDisplayName = function(isShow) {
|
||||||
|
var nameSpan = $('#' + this.videoSpanId + '>span.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;");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
|
||||||
|
if(!this.container)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$("#" + this.videoSpanId + " > .noMic").remove();
|
||||||
|
$("#" + this.videoSpanId + " > .noVideo").remove();
|
||||||
|
if(!devices.audio)
|
||||||
|
{
|
||||||
|
this.container.appendChild(
|
||||||
|
document.createElement("div")).setAttribute("class","noMic");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!devices.video)
|
||||||
|
{
|
||||||
|
this.container.appendChild(
|
||||||
|
document.createElement("div")).setAttribute("class","noVideo");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!devices.audio && !devices.video)
|
||||||
|
{
|
||||||
|
$("#" + this.videoSpanId + " > .noMic").css("background-position", "75%");
|
||||||
|
$("#" + this.videoSpanId + " > .noVideo").css("background-position", "25%");
|
||||||
|
$("#" + this.videoSpanId + " > .noVideo").css("background-color", "transparent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 stream element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
SmallVideo.createStreamElement = function (sid, stream) {
|
||||||
|
var isVideo = stream.getVideoTracks().length > 0;
|
||||||
|
|
||||||
|
var element = isVideo
|
||||||
|
? document.createElement('video')
|
||||||
|
: document.createElement('audio');
|
||||||
|
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
|
||||||
|
+ sid + '_' + APP.RTC.getStreamID(stream);
|
||||||
|
|
||||||
|
element.id = id;
|
||||||
|
element.autoplay = true;
|
||||||
|
element.oncontextmenu = function () { return false; };
|
||||||
|
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the data for the indicator
|
||||||
|
* @param id the id of the indicator
|
||||||
|
* @param percent the percent for connection quality
|
||||||
|
* @param object the data
|
||||||
|
*/
|
||||||
|
SmallVideo.prototype.updateStatsIndicator = function (percent, object) {
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.updateConnectionQuality(percent, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVideo.prototype.hideIndicator = function () {
|
||||||
|
if(this.connectionIndicator)
|
||||||
|
this.connectionIndicator.hideIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows audio muted indicator over small videos.
|
||||||
|
* @param {string} isMuted
|
||||||
|
*/
|
||||||
|
SmallVideo.prototype.showAudioIndicator = function(isMuted) {
|
||||||
|
var audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
|
||||||
|
|
||||||
|
if (isMuted === 'false') {
|
||||||
|
if (audioMutedSpan.length > 0) {
|
||||||
|
audioMutedSpan.popover('hide');
|
||||||
|
audioMutedSpan.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(audioMutedSpan.length == 0 ) {
|
||||||
|
audioMutedSpan = document.createElement('span');
|
||||||
|
audioMutedSpan.className = 'audioMuted';
|
||||||
|
UIUtil.setTooltip(audioMutedSpan,
|
||||||
|
"videothumbnail.mute",
|
||||||
|
"top");
|
||||||
|
|
||||||
|
this.container.appendChild(audioMutedSpan);
|
||||||
|
APP.translation.translateElement($('#' + this.videoSpanId + " > span"));
|
||||||
|
var mutedIndicator = document.createElement('i');
|
||||||
|
mutedIndicator.className = 'icon-mic-disabled';
|
||||||
|
audioMutedSpan.appendChild(mutedIndicator);
|
||||||
|
|
||||||
|
}
|
||||||
|
this.updateIconPositions();
|
||||||
|
}
|
||||||
|
this.isMuted = isMuted;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows video muted indicator over small videos.
|
||||||
|
*/
|
||||||
|
SmallVideo.prototype.showVideoIndicator = function(isMuted) {
|
||||||
|
var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
|
||||||
|
|
||||||
|
if (isMuted === false) {
|
||||||
|
if (videoMutedSpan.length > 0) {
|
||||||
|
videoMutedSpan.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(videoMutedSpan.length == 0) {
|
||||||
|
videoMutedSpan = document.createElement('span');
|
||||||
|
videoMutedSpan.className = 'videoMuted';
|
||||||
|
|
||||||
|
this.container.appendChild(videoMutedSpan);
|
||||||
|
|
||||||
|
var mutedIndicator = document.createElement('i');
|
||||||
|
mutedIndicator.className = 'icon-camera-disabled';
|
||||||
|
UIUtil.setTooltip(mutedIndicator,
|
||||||
|
"videothumbnail.videomute",
|
||||||
|
"top");
|
||||||
|
videoMutedSpan.appendChild(mutedIndicator);
|
||||||
|
//translate texts for muted indicator
|
||||||
|
APP.translation.translateElement($('#' + this.videoSpanId + " > span > i"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateIconPositions();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SmallVideo.prototype.enableDominantSpeaker = function (isEnable)
|
||||||
|
{
|
||||||
|
var displayName = this.resourceJid;
|
||||||
|
var nameSpan = $('#' + this.videoSpanId + '>span.displayname');
|
||||||
|
if (nameSpan.length > 0)
|
||||||
|
displayName = nameSpan.html();
|
||||||
|
|
||||||
|
console.log("UI enable dominant speaker",
|
||||||
|
displayName,
|
||||||
|
this.resourceJid,
|
||||||
|
isEnable);
|
||||||
|
|
||||||
|
|
||||||
|
if (!this.container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var video = $('#' + this.videoSpanId + '>video');
|
||||||
|
|
||||||
|
if (video && video.length > 0) {
|
||||||
|
if (isEnable) {
|
||||||
|
this.showDisplayName(LargeVideo.isLargeVideoOnTop());
|
||||||
|
|
||||||
|
if (!this.container.classList.contains("dominantspeaker"))
|
||||||
|
this.container.classList.add("dominantspeaker");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.showDisplayName(false);
|
||||||
|
|
||||||
|
if (this.container.classList.contains("dominantspeaker"))
|
||||||
|
this.container.classList.remove("dominantspeaker");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SmallVideo.prototype.updateIconPositions = function () {
|
||||||
|
var audioMutedSpan = $('#' + this.videoSpanId + '>span.audioMuted');
|
||||||
|
var connectionIndicator = $('#' + this.videoSpanId + '>div.connectionindicator');
|
||||||
|
var videoMutedSpan = $('#' + this.videoSpanId + '>span.videoMuted');
|
||||||
|
if(connectionIndicator.length > 0
|
||||||
|
&& connectionIndicator[0].style.display != "none") {
|
||||||
|
audioMutedSpan.css({right: "23px"});
|
||||||
|
videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
audioMutedSpan.css({right: "0px"});
|
||||||
|
videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the element indicating the moderator(owner) of the conference.
|
||||||
|
*
|
||||||
|
* @param parentElement the parent element where the owner indicator will
|
||||||
|
* be added
|
||||||
|
*/
|
||||||
|
SmallVideo.prototype.createModeratorIndicatorElement = function () {
|
||||||
|
// Show moderator indicator
|
||||||
|
var indicatorSpan = $('#' + this.videoSpanId + ' .focusindicator');
|
||||||
|
|
||||||
|
if (!indicatorSpan || indicatorSpan.length === 0) {
|
||||||
|
indicatorSpan = document.createElement('span');
|
||||||
|
indicatorSpan.className = 'focusindicator';
|
||||||
|
|
||||||
|
this.container.appendChild(indicatorSpan);
|
||||||
|
indicatorSpan = $('#' + this.videoSpanId + ' .focusindicator');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indicatorSpan.children().length !== 0)
|
||||||
|
return;
|
||||||
|
var moderatorIndicator = document.createElement('i');
|
||||||
|
moderatorIndicator.className = 'fa fa-star';
|
||||||
|
indicatorSpan[0].appendChild(moderatorIndicator);
|
||||||
|
|
||||||
|
UIUtil.setTooltip(indicatorSpan[0],
|
||||||
|
"videothumbnail.moderator",
|
||||||
|
"top");
|
||||||
|
|
||||||
|
//translates text in focus indicators
|
||||||
|
APP.translation.translateElement($('#' + this.videoSpanId + ' .focusindicator'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SmallVideo.prototype.getSrc = function () {
|
||||||
|
return APP.RTC.getVideoSrc($('#' + this.videoSpanId).find("video").get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVideo.prototype.focus = function(isFocused)
|
||||||
|
{
|
||||||
|
if(!isFocused) {
|
||||||
|
this.container.classList.remove("videoContainerFocused");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.container.classList.add("videoContainerFocused");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SmallVideo.prototype.hasVideo = function () {
|
||||||
|
return $("#" + this.videoSpanId).find("video").length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SmallVideo;
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue