Refactors VideoLayout.js.

This commit is contained in:
hristoterezov 2015-06-23 11:00:46 +03:00
parent 38b180ad81
commit 6a492d96c2
14 changed files with 19105 additions and 19100 deletions

View File

@ -19,7 +19,7 @@
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<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 -->
<link rel="stylesheet" href="css/font.css?v=7"/>
<link rel="stylesheet" href="css/toastr.css?v=1">

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ var DataChannels =
// selections so that it can do adaptive simulcast,
// we want the notification to trigger even if userJid is undefined,
// or null.
var userJid = APP.UI.getLargeVideoState().userResourceJid;
var userJid = APP.UI.getLargeVideoJid();
// we want the notification to trigger even if userJid is undefined,
// or null.
onSelectedEndpointChanged(userJid);

View File

@ -143,7 +143,7 @@ function registerListeners() {
}
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
UI.getLargeVideoState().userResourceJid);
UI.getLargeVideoJid());
});
APP.desktopsharing.addListener(function () {
ToolbarToggler.showDesktopSharingButton();
@ -215,8 +215,6 @@ function registerListeners() {
break;
case 'recvonly':
el.hide();
// FIXME: Check if we have to change large video
//VideoLayout.updateLargeVideo(el);
break;
}
}
@ -265,6 +263,11 @@ function setVideoMute(mute, options) {
options);
}
function onResize()
{
Chat.resizeChat();
VideoLayout.resizeLargeVideoContainer();
}
function bindEvents()
{
@ -272,16 +275,9 @@ function bindEvents()
* Resizes and repositions videos in full screen mode.
*/
$(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
}
);
onResize);
$(window).resize(function () {
VideoLayout.resizeLargeVideoContainer();
VideoLayout.positionLarge();
});
$(window).resize(onResize);
}
UI.start = function (init) {
@ -322,7 +318,6 @@ UI.start = function (init) {
$("#welcome_page").hide();
VideoLayout.resizeLargeVideoContainer();
$("#videospace").mousemove(function () {
return ToolbarToggler.showToolbar();
});
@ -550,9 +545,8 @@ function onMucMemberJoined(jid, id, displayName) {
VideoLayout.ensurePeerContainerExists(jid,id);
}
function onMucPresenceStatus( jid, info) {
VideoLayout.setPresenceStatus(
'participant_' + Strophe.getResourceFromJid(jid), info.status);
function onMucPresenceStatus(jid, info) {
VideoLayout.setPresenceStatus(Strophe.getResourceFromJid(jid), info.status);
}
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() {
@ -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)

View File

@ -13,14 +13,13 @@ function setVisibility(selector, show) {
function isUserMuted(jid) {
// XXX(gp) we may want to rename this method to something like
// isUserStreaming, for example.
if (jid && jid != APP.xmpp.myJid()) {
if (jid != APP.xmpp.myJid()) {
var resource = Strophe.getResourceFromJid(jid);
if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
return true;
}
}
if(jid && jid == APP.xmpp.myJid())
else
{
var localVideo = APP.RTC.localVideo;
return (!localVideo || localVideo.isMuted());
@ -117,7 +116,7 @@ var Avatar = {
//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
//currently shown
if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
if (activeSpeakerJid === jid && require("../videolayout/LargeVideo").isLargeVideoOnTop()) {
setVisibility($("#largeVideo"), !show);
setVisibility($('#activeSpeaker'), show);
setVisibility(avatar, false);
@ -137,10 +136,6 @@ var Avatar = {
* @param jid of the current active speaker
*/
updateActiveSpeakerAvatarSrc: function (jid) {
if (!jid) {
jid = APP.xmpp.findJidFromResource(
require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
}
var avatar = $("#activeSpeakerAvatar")[0];
var url = getGravatarUrl(users[jid],
interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);

View File

@ -165,10 +165,10 @@ function presentationAdded(event, jid, presUrl, currentSlide) {
+ Strophe.getResourceFromJid(jid)
+ '_' + 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();
var controlsEnabled = false;

View File

@ -5,6 +5,7 @@ var SettingsMenu = require("./settings/SettingsMenu");
var VideoLayout = require("../videolayout/VideoLayout");
var ToolbarToggler = require("../toolbars/ToolbarToggler");
var UIUtil = require("../util/UIUtil");
var LargeVideo = require("../videolayout/LargeVideo");
/**
* Toggler for the chat, contact list, settings menu, etc..
@ -18,90 +19,6 @@ var PanelToggler = (function(my) {
'#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
* @param object the window that should be shown
@ -135,7 +52,7 @@ var PanelToggler = (function(my) {
else {
// Undock the toolbar when the chat is shown and if we're in a
// video mode.
if (VideoLayout.isLargeVideoVisible()) {
if (LargeVideo.isLargeVideoVisible()) {
ToolbarToggler.dockToolbar(false);
}
@ -180,7 +97,7 @@ var PanelToggler = (function(my) {
$('#chatspace').trigger('shown');
};
resizeVideoArea(Chat.isVisible(), chatCompleteFunction);
VideoLayout.resizeVideoArea(!Chat.isVisible(), chatCompleteFunction);
toggle(Chat,
'#chatspace',
@ -203,7 +120,7 @@ var PanelToggler = (function(my) {
my.toggleContactList = function () {
var completeFunction = ContactList.isVisible() ?
function() {} : function () { $('#contactlist').trigger('shown');};
resizeVideoArea(ContactList.isVisible(), completeFunction);
VideoLayout.resizeVideoArea(!ContactList.isVisible(), completeFunction);
toggle(ContactList,
'#contactlist',
@ -218,7 +135,7 @@ var PanelToggler = (function(my) {
* Opens / closes the settings menu
*/
my.toggleSettingsMenu = function() {
resizeVideoArea(SettingsMenu.isVisible(), function (){});
VideoLayout.resizeVideoArea(!SettingsMenu.isVisible(), function (){});
toggle(SettingsMenu,
'#settingsmenu',
null,

View File

@ -5,10 +5,12 @@ module.exports = {
/**
* Returns the available video width.
*/
getAvailableVideoWidth: function () {
getAvailableVideoWidth: function (isVisible) {
var PanelToggler = require("../side_pannels/SidePanelToggler");
if(typeof isVisible === "undefined" || isVisible === null)
isVisible = PanelToggler.isVisible();
var rightPanelWidth
= PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
= isVisible ? PanelToggler.getPanelSize()[0] : 0;
return window.innerWidth - rightPanelWidth;
},

View File

@ -5,7 +5,7 @@ var JitsiPopover = require("../util/JitsiPopover");
* @param videoContainer the video container associated with the indicator.
* @constructor
*/
function ConnectionIndicator(videoContainer, jid, VideoLayout)
function ConnectionIndicator(videoContainer, jid)
{
this.videoContainer = videoContainer;
this.bandwidth = null;
@ -17,7 +17,6 @@ function ConnectionIndicator(videoContainer, jid, VideoLayout)
this.popover = null;
this.jid = jid;
this.create();
this.videoLayout = VideoLayout;
}
/**
@ -153,10 +152,10 @@ ConnectionIndicator.prototype.generateText = function () {
translate("connectionindicator.resolution") + "</span></td>" +
"<td>" + resolution + "</td></tr></table>";
if(this.videoContainer.id == "localVideoContainer") {
if(this.videoContainer.videoSpanId == "localVideoContainer") {
result += "<div class=\"jitsipopover_showmore\" " +
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
this.videoContainer.id + "')\" data-i18n='connectionindicator." +
this.jid + "')\" data-i18n='connectionindicator." +
(this.showMoreValue ? "less" : "more") + "'>" +
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
"</div><br />";
@ -318,9 +317,9 @@ ConnectionIndicator.prototype.create = function () {
this.connectionIndicatorContainer = document.createElement("div");
this.connectionIndicatorContainer.className = "connectionindicator";
this.connectionIndicatorContainer.style.display = "none";
this.videoContainer.appendChild(this.connectionIndicatorContainer);
this.videoContainer.container.appendChild(this.connectionIndicatorContainer);
this.popover = new JitsiPopover(
$("#" + this.videoContainer.id + " > .connectionindicator"),
$("#" + this.videoContainer.videoSpanId + " > .connectionindicator"),
{content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
APP.translation.translateString("connectionindicator.na") + "</div>",
skin: "black"});
@ -360,7 +359,7 @@ function (percent, object) {
{
if(this.connectionIndicatorContainer.style.display == "none") {
this.connectionIndicatorContainer.style.display = "block";
this.videoLayout.updateMutePosition(this.videoContainer.id);
this.videoContainer.updateIconPositions();
}
}
this.bandwidth = object.bandwidth;

View File

@ -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;

View File

@ -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;

View File

@ -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'>&nbsp;</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;

View File

@ -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