jiti-meet/modules/UI/videolayout/LocalVideo.js

207 lines
6.6 KiB
JavaScript
Raw Normal View History

2016-05-01 18:35:18 +00:00
/* global $, config, interfaceConfig, APP, JitsiMeetJS */
/* eslint-disable no-unused-vars */
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { VideoTrack } from '../../../react/features/base/media';
/* eslint-enable no-unused-vars */
2016-11-11 15:00:54 +00:00
const logger = require("jitsi-meet-logger").getLogger(__filename);
2015-12-14 12:26:50 +00:00
import UIEvents from "../../../service/UI/UIEvents";
import SmallVideo from "./SmallVideo";
2016-01-06 22:39:13 +00:00
const TrackEvents = JitsiMeetJS.events.track;
2015-12-01 12:53:01 +00:00
function LocalVideo(VideoLayout, emitter) {
2015-06-23 08:00:46 +00:00
this.videoSpanId = "localVideoContainer";
this.container = $("#localVideoContainer").get(0);
this.localVideoId = null;
this.bindHoverHandler();
if(config.enableLocalVideoFlip)
this._buildContextMenu();
this.isLocal = true;
2015-12-01 12:53:01 +00:00
this.emitter = emitter;
Object.defineProperty(this, 'id', {
get: function () {
2016-07-08 01:44:04 +00:00
return APP.conference.getMyUserId();
}
});
this.initBrowserSpecificProperties();
SmallVideo.call(this, VideoLayout);
// Set default display name.
this.setDisplayName();
2016-09-28 21:31:40 +00:00
this.addAudioLevelIndicator();
this.updateIndicators();
2015-06-23 08:00:46 +00:00
}
LocalVideo.prototype = Object.create(SmallVideo.prototype);
LocalVideo.prototype.constructor = LocalVideo;
/**
* Sets the display name for the given video span id.
*/
LocalVideo.prototype.setDisplayName = function(displayName) {
2015-06-23 08:00:46 +00:00
if (!this.container) {
2016-11-11 15:00:54 +00:00
logger.warn(
"Unable to set displayName - " + this.videoSpanId +
" does not exist");
2015-06-23 08:00:46 +00:00
return;
}
this.updateDisplayName({
allowEditing: true,
displayName: displayName,
displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
elementID: 'localDisplayName',
participantID: this.id
});
};
2015-06-23 08:00:46 +00:00
2015-12-14 12:26:50 +00:00
LocalVideo.prototype.changeVideo = function (stream) {
this.videoStream = stream;
2015-06-23 08:00:46 +00:00
2015-12-14 12:26:50 +00:00
let localVideoClick = (event) => {
// TODO Checking the classList is a workround to allow events to bubble
// into the DisplayName component if it was clicked. React's synthetic
// events will fire after jQuery handlers execute, so stop propogation
// at this point will prevent DisplayName from getting click events.
// This workaround should be removeable once LocalVideo is a React
// Component because then the components share the same eventing system.
const { classList } = event.target;
const clickedOnDisplayName = classList.contains('displayname')
|| classList.contains('editdisplayname');
// FIXME: with Temasys plugin event arg is not an event, but
// the clicked object itself, so we have to skip this call
if (event.stopPropagation && !clickedOnDisplayName) {
event.stopPropagation();
}
if (!clickedOnDisplayName) {
this.VideoLayout.handleVideoThumbClicked(this.id);
}
2015-12-14 12:26:50 +00:00
};
2015-06-23 08:00:46 +00:00
2015-12-14 12:26:50 +00:00
let localVideoContainerSelector = $('#localVideoContainer');
localVideoContainerSelector.off('click');
localVideoContainerSelector.on('click', localVideoClick);
2015-06-23 08:00:46 +00:00
this.localVideoId = 'localVideo_' + stream.getId();
2015-06-23 08:00:46 +00:00
var localVideoContainer = document.getElementById('localVideoWrapper');
/* jshint ignore:start */
ReactDOM.render(
<Provider store = { APP.store }>
<VideoTrack
id = { this.localVideoId }
videoTrack = {{ jitsiTrack: stream }} />
</Provider>,
localVideoContainer
);
/* jshint ignore:end */
2015-06-23 08:00:46 +00:00
let isVideo = stream.videoType != "desktop";
this._enableDisableContextMenu(isVideo);
this.setFlipX(isVideo? APP.settings.getLocalFlipX() : false);
2015-06-23 08:00:46 +00:00
2016-01-06 22:39:13 +00:00
let endedHandler = () => {
// Only remove if there is no video and not a transition state.
// Previous non-react logic created a new video element with each track
// removal whereas react reuses the video component so it could be the
// stream ended but a new one is being used.
if (this.videoStream.isEnded()) {
ReactDOM.unmountComponentAtNode(localVideoContainer);
}
// when removing only the video element and we are on stage
// update the stage
if (this.isCurrentlyOnLargeVideo()) {
this.VideoLayout.updateLargeVideo(this.id);
}
stream.off(TrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
2016-01-06 22:39:13 +00:00
};
stream.on(TrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
};
2015-06-23 08:00:46 +00:00
2016-05-01 18:35:18 +00:00
/**
* Shows or hides the local video container.
* @param {boolean} true to make the local video container visible, false
* otherwise
*/
LocalVideo.prototype.setVisible = function(visible) {
// We toggle the hidden class as an indication to other interested parties
// that this container has been hidden on purpose.
$("#localVideoContainer").toggleClass("hidden");
// We still show/hide it as we need to overwrite the style property if we
// want our action to take effect. Toggling the display property through
// the above css class didn't succeed in overwriting the style.
if (visible) {
$("#localVideoContainer").show();
}
else {
$("#localVideoContainer").hide();
}
};
/**
* Sets the flipX state of the video.
* @param val {boolean} true for flipped otherwise false;
*/
LocalVideo.prototype.setFlipX = function (val) {
this.emitter.emit(UIEvents.LOCAL_FLIPX_CHANGED, val);
if(!this.localVideoId)
return;
if(val) {
this.selectVideoElement().addClass("flipVideoX");
} else {
this.selectVideoElement().removeClass("flipVideoX");
}
};
/**
* Builds the context menu for the local video.
*/
LocalVideo.prototype._buildContextMenu = function () {
$.contextMenu({
selector: '#' + this.videoSpanId,
zIndex: 10000,
items: {
flip: {
name: "Flip",
callback: () => {
let val = !APP.settings.getLocalFlipX();
this.setFlipX(val);
APP.settings.setLocalFlipX(val);
}
}
},
events: {
show : function(options){
options.items.flip.name =
APP.translation.generateTranslationHTML(
"videothumbnail.flip");
}
}
});
};
/**
* Enables or disables the context menu for the local video.
* @param enable {boolean} true for enable, false for disable
*/
LocalVideo.prototype._enableDisableContextMenu = function (enable) {
if($('#' + this.videoSpanId).contextMenu)
$('#' + this.videoSpanId).contextMenu(enable);
};
2015-12-14 12:26:50 +00:00
export default LocalVideo;