feat(tile-view): double click to pin
This commit is contained in:
parent
fc75adc6ff
commit
ebcde745ef
|
@ -595,17 +595,7 @@ UI.removeListener = function(type, listener) {
|
|||
*/
|
||||
UI.emitEvent = (type, ...options) => eventEmitter.emit(type, ...options);
|
||||
|
||||
UI.clickOnVideo = function(videoNumber) {
|
||||
const videos = $('#remoteVideos .videocontainer:not(#mixedstream)');
|
||||
const videosLength = videos.length;
|
||||
|
||||
if (videosLength <= videoNumber) {
|
||||
return;
|
||||
}
|
||||
const videoIndex = videoNumber === 0 ? 0 : videosLength - videoNumber;
|
||||
|
||||
videos[videoIndex].click();
|
||||
};
|
||||
UI.clickOnVideo = videoNumber => VideoLayout.togglePin(videoNumber);
|
||||
|
||||
// Used by torture.
|
||||
UI.showToolbar = timeout => APP.store.dispatch(showToolbox(timeout));
|
||||
|
|
|
@ -15,11 +15,14 @@ export default function SharedVideoThumb(participant, videoType, VideoLayout) {
|
|||
this.videoSpanId = 'sharedVideoContainer';
|
||||
this.container = this.createContainer(this.videoSpanId);
|
||||
this.$container = $(this.container);
|
||||
this.container.onclick = this.videoClick.bind(this);
|
||||
|
||||
this.bindHoverHandler();
|
||||
SmallVideo.call(this, VideoLayout);
|
||||
this.isVideoMuted = true;
|
||||
this.setDisplayName(participant.name);
|
||||
|
||||
this.container.onclick = this._onContainerClick;
|
||||
this.container.ondblclick = this._onContainerDoubleClick;
|
||||
}
|
||||
SharedVideoThumb.prototype = Object.create(SmallVideo.prototype);
|
||||
SharedVideoThumb.prototype.constructor = SharedVideoThumb;
|
||||
|
@ -61,13 +64,6 @@ SharedVideoThumb.prototype.createContainer = function(spanId) {
|
|||
return container;
|
||||
};
|
||||
|
||||
/**
|
||||
* The thumb click handler.
|
||||
*/
|
||||
SharedVideoThumb.prototype.videoClick = function() {
|
||||
this._togglePin();
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes RemoteVideo from the page.
|
||||
*/
|
||||
|
|
|
@ -61,7 +61,8 @@ function LocalVideo(VideoLayout, emitter, streamEndedCallback) {
|
|||
this.addAudioLevelIndicator();
|
||||
this.updateIndicators();
|
||||
|
||||
this.container.onclick = this._onContainerClick.bind(this);
|
||||
this.container.onclick = this._onContainerClick;
|
||||
this.container.ondblclick = this._onContainerDoubleClick;
|
||||
}
|
||||
|
||||
LocalVideo.prototype = Object.create(SmallVideo.prototype);
|
||||
|
@ -253,40 +254,6 @@ LocalVideo.prototype.updateDOMLocation = function() {
|
|||
this._updateVideoElement();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when the thumbnail is clicked. Will directly call
|
||||
* VideoLayout to handle thumbnail click if certain elements have not been
|
||||
* clicked.
|
||||
*
|
||||
* @param {MouseEvent} event - The click event to intercept.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
LocalVideo.prototype._onContainerClick = function(event) {
|
||||
// TODO Checking the classes 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 $source = $(event.target || event.srcElement);
|
||||
const { classList } = event.target;
|
||||
|
||||
const clickedOnDisplayName
|
||||
= $source.parents('.displayNameContainer').length > 0;
|
||||
const clickedOnPopover = $source.parents('.popover').length > 0
|
||||
|| classList.contains('popover');
|
||||
const ignoreClick = clickedOnDisplayName || clickedOnPopover;
|
||||
|
||||
if (event.stopPropagation && !ignoreClick) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (!ignoreClick) {
|
||||
this._togglePin();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the React Element for displaying video in {@code LocalVideo}.
|
||||
*
|
||||
|
|
|
@ -22,8 +22,7 @@ import {
|
|||
} from '../../../react/features/remote-video-menu';
|
||||
import {
|
||||
LAYOUTS,
|
||||
getCurrentLayout,
|
||||
shouldDisplayTileView
|
||||
getCurrentLayout
|
||||
} from '../../../react/features/video-layout';
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
|
@ -89,7 +88,8 @@ function RemoteVideo(user, VideoLayout, emitter) {
|
|||
this._setAudioVolume = this._setAudioVolume.bind(this);
|
||||
this._stopRemoteControl = this._stopRemoteControl.bind(this);
|
||||
|
||||
this.container.onclick = this._onContainerClick.bind(this);
|
||||
this.container.onclick = this._onContainerClick;
|
||||
this.container.ondblclick = this._onContainerDoubleClick;
|
||||
}
|
||||
|
||||
RemoteVideo.prototype = Object.create(SmallVideo.prototype);
|
||||
|
@ -613,36 +613,6 @@ RemoteVideo.prototype.removePresenceLabel = function() {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when the thumbnail is clicked. Will directly call
|
||||
* VideoLayout to handle thumbnail click if certain elements have not been
|
||||
* clicked.
|
||||
*
|
||||
* @param {MouseEvent} event - The click event to intercept.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
RemoteVideo.prototype._onContainerClick = function(event) {
|
||||
const $source = $(event.target || event.srcElement);
|
||||
const { classList } = event.target;
|
||||
|
||||
const ignoreClick = $source.parents('.popover').length > 0
|
||||
|| classList.contains('popover');
|
||||
|
||||
if (!ignoreClick) {
|
||||
this._togglePin();
|
||||
}
|
||||
|
||||
// On IE we need to populate this handler on video <object> and it does not
|
||||
// give event instance as an argument, so we check here for methods.
|
||||
if (event.stopPropagation && event.preventDefault && !ignoreClick) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
RemoteVideo.createContainer = function(spanId) {
|
||||
const container = document.createElement('span');
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ function SmallVideo(VideoLayout) {
|
|||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onPopoverHover = this._onPopoverHover.bind(this);
|
||||
this.updateView = this.updateView.bind(this);
|
||||
|
||||
this._onContainerClick = this._onContainerClick.bind(this);
|
||||
this._onContainerDoubleClick = this._onContainerDoubleClick.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -821,12 +824,71 @@ SmallVideo.prototype.updateIndicators = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* Pins the participant displayed by this thumbnail or unpins if already pinned.
|
||||
* Callback invoked when the thumbnail is double clicked. Will pin the
|
||||
* participant if in tile view.
|
||||
*
|
||||
* @param {MouseEvent} event - The click event to intercept.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype._togglePin = function() {
|
||||
SmallVideo.prototype._onContainerDoubleClick = function(event) {
|
||||
if (this._pinningRequiresDoubleClick() && this._shouldTriggerPin(event)) {
|
||||
APP.store.dispatch(pinParticipant(this.id));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback invoked when the thumbnail is clicked and potentially trigger
|
||||
* pinning of the participant.
|
||||
*
|
||||
* @param {MouseEvent} event - The click event to intercept.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype._onContainerClick = function(event) {
|
||||
const triggerPin = this._shouldTriggerPin(event)
|
||||
&& !this._pinningRequiresDoubleClick();
|
||||
|
||||
if (event.stopPropagation && triggerPin) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (triggerPin) {
|
||||
this.togglePin();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not a click event is targeted at certain elements which
|
||||
* should not trigger a pin.
|
||||
*
|
||||
* @param {MouseEvent} event - The click event to intercept.
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
SmallVideo.prototype._shouldTriggerPin = function(event) {
|
||||
// TODO Checking the classes 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 $source = $(event.target || event.srcElement);
|
||||
|
||||
return $source.parents('.displayNameContainer').length === 0
|
||||
&& $source.parents('.popover').length === 0
|
||||
&& !event.target.classList.contains('popover');
|
||||
};
|
||||
|
||||
/**
|
||||
* Pins the participant displayed by this thumbnail or unpins if already pinned.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
SmallVideo.prototype.togglePin = function() {
|
||||
const pinnedParticipant
|
||||
= getPinnedParticipant(APP.store.getState()) || {};
|
||||
const participantIdToPin
|
||||
|
@ -836,6 +898,17 @@ SmallVideo.prototype._togglePin = function() {
|
|||
APP.store.dispatch(pinParticipant(participantIdToPin));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether or not clicking to pin the participant needs to be a double
|
||||
* click instead of a single click.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
SmallVideo.prototype._pinningRequiresDoubleClick = function() {
|
||||
return shouldDisplayTileView(APP.store.getState());
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the React element responsible for showing connection status, dominant
|
||||
* speaker, and raised hand icons.
|
||||
|
|
|
@ -391,6 +391,19 @@ const VideoLayout = {
|
|||
return id || null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Triggers a thumbnail to pin or unpin itself.
|
||||
*
|
||||
* @param {number} videoNumber - The index of the video to toggle pin on.
|
||||
* @private
|
||||
*/
|
||||
togglePin(videoNumber) {
|
||||
const videos = getAllThumbnails();
|
||||
const videoView = videos[videoNumber];
|
||||
|
||||
videoView && videoView.togglePin();
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback invoked to update display when the pin participant has changed.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue