feat(vertical-filmstrip): Initial implementation

- Add a class to the body when in vertical filmstrip mode
- Override styles as necessary to support the mode
- Add an option to make tooltips display from the left
- Move the HD Label to the bottom left
- Move the remote video menu to the bottom left, move the mute
  icons to the bottom right
- Scale the local video's height and width to fit the filmstrip
This commit is contained in:
Leonard Kim 2017-05-17 15:40:41 -07:00
parent 82ecfac4ee
commit aabe641047
9 changed files with 306 additions and 31 deletions

View File

@ -44,4 +44,28 @@
border-width: 5px;
border-bottom-width: 0;
}
/**
* Override default "top" styles to support popovers appearing from the
* left of the popover trigger element.
*/
&.left {
margin-left: -$popoverMenuPadding;
margin-top: 0;
.arrow {
border-color: transparent transparent transparent $popoverBg;
border-width: 5px 0px 5px 5px;
margin-left: 0;
margin-top: -5px;
}
.jitsipopover {
&__menu-padding {
bottom: 0;
height: 100%;
width: $popoverMenuPadding;
}
}
}
}

View File

@ -0,0 +1,150 @@
/**
* Override other styles to support vertical filmstrip mode.
*/
.vertical-filmstrip {
.filmstrip {
align-items: flex-end;
box-sizing: border-box;
display: flex;
flex-direction: column-reverse;
height: 100%;
/**
* Hide videos by making them slight to the right.
*/
.filmstrip__videos {
right: 0;
transition: right 2s;
&.hidden {
bottom: auto;
right: -196px;
}
}
#filmstripLocalVideo {
height: auto;
justify-content: flex-end;
}
/**
* Remove unnecssary padding that is normally used to prevent horizontal
* filmstrip from overlapping the left edge of the screen.
*/
#filmstripLocalVideo,
#filmstripRemoteVideos {
padding: 0;
}
#filmstripRemoteVideos {
display: flex;
flex: 1;
flex-direction: column;
height: auto;
overflow-x: hidden !important;
.remote-videos-container {
flex-direction: column;
}
}
/**
* Rotate the hide filmstrip icon so it points towards the right edge
* of the screen.
*/
&__toolbar {
transform: rotate(-90deg);
}
/**
* Move the remote video menu trigger to the bottom left of the
* video thumbnail.
*/
.remotevideomenu {
bottom: 0;
left: 0;
top: auto;
right: auto;
transform: rotate(-90deg);
}
#remoteVideos {
flex-direction: column-reverse;
height: 100%;
}
.videocontainer {
/**
* Move status icons to the bottom right of the thumbnail.
*/
&__toolbar {
text-align: right;
.toolbar-icon {
float: none;
}
}
}
}
.video-state-indicator {
bottom: 30px;
left: 30px;
right: auto;
top: auto;
/**
* Move the label to the bottom left of the screen
*/
&#videoResolutionLabel {
left: 60px;
z-index: $poweredByZ;
/**
* Open the menu above the label.
*/
.video-state-indicator-menu {
bottom: calc(100% - 15px);
left: -10px;
/**
* Create padding for mouse travel on hover.
*/
padding-bottom: 20px;
right: auto;
top: auto;
.video-state-indicator-menu-options {
margin: 0;
/**
* The menu arrow should point down
*/
&::after {
border-color: $popoverBg transparent transparent;
bottom: -10px;
left: 15px;
right: auto;
top: auto;
}
}
}
}
&#recordingLabel {
left: 110px;
z-index: $poweredByZ;
}
}
/**
* Move toastr closer to the bottom of the screen and move left to avoid
* overlapping of videos when they are configured at default height.
*/
#toast-container {
&.notification-bottom-right {
bottom: 25px;
right: 130 + 2 * ($thumbnailVideoMargin + $thumbnailsBorder) + $thumbnailVideoBorder;
}
}
}

View File

@ -73,5 +73,6 @@
@import 'policy';
@import 'filmstrip';
@import 'unsupported-browser/main';
@import 'vertical_filmstrip_overrides';
/* Modules END */

View File

@ -55,6 +55,12 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
* Whether to only show the filmstrip (and hide the toolbar).
*/
filmStripOnly: false,
/**
* Whether to show thumbnails in filmstrip as a column instead of as a row.
*/
VERTICAL_FILMSTRIP: false,
//A html text to be shown to guests on the close page, false disables it
CLOSE_PAGE_GUEST_HINT: false,
RANDOM_AVATAR_URL_PREFIX: false,

View File

@ -339,6 +339,10 @@ UI.start = function () {
JitsiPopover.enabled = false;
}
if (interfaceConfig.VERTICAL_FILMSTRIP) {
$("body").addClass("vertical-filmstrip");
}
document.title = interfaceConfig.APP_NAME;
if (!interfaceConfig.filmStripOnly) {

View File

@ -1,4 +1,74 @@
/* global $ */
const positionConfigurations = {
left: {
// Align the popover's right side to the target element.
my: 'right',
// Align the popover to the left side of the target element.
at: 'left',
// Force the popover to fit within the viewport.
collision: 'fit',
/**
* Callback invoked by jQuery UI tooltip.
*
* @param {Object} position - The top and bottom position the popover
* element should be set at.
* @param {Object} element. - Additional size and position information
* about the popover element and target.
* @param {Object} elements.element - Has position and size related data
* for the popover element itself.
* @param {Object} elements.target - Has position and size related data
* for the target element the popover displays from.
*/
using: function setPositionLeft(position, elements) {
const { element, target } = elements;
$('.jitsipopover').css({
display: 'table',
left: position.left,
top: position.top
});
// Move additional padding to the right edge of the popover and
// allow css to take care of width. The padding is used to maintain
// a hover state between the target and the popover.
$('.jitsipopover > .jitsipopover__menu-padding').css({
left: element.width
});
// Find the distance from the top of the popover to the center of
// the target and use that value to position the arrow to point to
// it.
const verticalCenterOfTarget = target.height / 2;
const verticalDistanceFromTops = target.top - element.top;
const verticalPositionOfTargetCenter
= verticalDistanceFromTops + verticalCenterOfTarget;
$('.jitsipopover > .arrow').css({
left: element.width,
top: verticalPositionOfTargetCenter
});
}
},
top: {
my: "bottom",
at: "top",
collision: "fit",
using: function setPositionTop(position, elements) {
var calcLeft = elements.target.left - elements.element.left +
elements.target.width/2;
$(".jitsipopover").css(
{top: position.top, left: position.left, display: "table"});
$(".jitsipopover > .arrow").css({left: calcLeft});
$(".jitsipopover > .jitsipopover__menu-padding").css(
{left: calcLeft - 50});
}
}
};
var JitsiPopover = (function () {
/**
* The default options
@ -7,7 +77,8 @@ var JitsiPopover = (function () {
skin: 'white',
content: '',
hasArrow: true,
onBeforePosition: undefined
onBeforePosition: undefined,
position: 'top'
};
/**
@ -21,7 +92,6 @@ var JitsiPopover = (function () {
function JitsiPopover(element, options)
{
this.options = Object.assign({}, defaultOptions, options);
this.elementIsHovered = false;
this.popoverIsHovered = false;
this.popoverShown = false;
@ -45,12 +115,15 @@ var JitsiPopover = (function () {
* Returns template for popover
*/
JitsiPopover.prototype.getTemplate = function () {
const { hasArrow, position, skin } = this.options;
let arrow = '';
if (this.options.hasArrow) {
if (hasArrow) {
arrow = '<div class="arrow"></div>';
}
return (
`<div class="jitsipopover ${this.options.skin}">
`<div class="jitsipopover ${skin} ${position}">
${arrow}
<div class="jitsipopover__content"></div>
<div class="jitsipopover__menu-padding"></div>
@ -129,21 +202,14 @@ var JitsiPopover = (function () {
* Refreshes the position of the popover.
*/
JitsiPopover.prototype.refreshPosition = function () {
$(".jitsipopover").position({
my: "bottom",
at: "top",
collision: "fit",
of: this.element,
using: function (position, elements) {
var calcLeft = elements.target.left - elements.element.left +
elements.target.width/2;
$(".jitsipopover").css(
{top: position.top, left: position.left, display: "table"});
$(".jitsipopover > .arrow").css({left: calcLeft});
$(".jitsipopover > .jitsipopover__menu-padding").css(
{left: calcLeft - 50});
const positionOptions = Object.assign(
{},
positionConfigurations[this.options.position],
{
of: this.element
}
});
);
$(".jitsipopover").position(positionOptions);
};
/**

View File

@ -1,4 +1,4 @@
/* global $, APP */
/* global $, APP, interfaceConfig */
/* jshint -W101 */
import JitsiPopover from "../util/JitsiPopover";
@ -309,7 +309,8 @@ ConnectionIndicator.prototype.create = function () {
this.popover = new JitsiPopover($(element), {
content: popoverContent,
skin: "black",
onBeforePosition: el => APP.translation.translateElement(el)
onBeforePosition: el => APP.translation.translateElement(el),
position: interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top'
});
// override popover show method to make sure we will update the content

View File

@ -178,7 +178,10 @@ const Filmstrip = {
* @returns {number} height
*/
getFilmstripHeight() {
if (this.isFilmstripVisible()) {
// FIXME Make it more clear the getFilmstripHeight check is used in
// horizontal film strip mode for calculating how tall large video
// display should be.
if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
return $(`.${this.filmstripContainerClassName}`).outerHeight();
} else {
return 0;
@ -365,13 +368,27 @@ const Filmstrip = {
(remoteLocalWidthRatio * numberRemoteThumbs + 1), availableHeight *
interfaceConfig.LOCAL_THUMBNAIL_RATIO);
const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
const removeVideoWidth = lW * remoteLocalWidthRatio;
let localVideo;
if (interfaceConfig.VERTICAL_FILMSTRIP) {
// scale both width and height
localVideo = {
thumbWidth: removeVideoWidth,
thumbHeight: h * remoteLocalWidthRatio
};
} else {
localVideo = {
thumbWidth: lW,
thumbHeight: h
};
}
return {
localVideo:{
thumbWidth: lW,
thumbHeight: h
},
localVideo,
remoteVideo: {
thumbWidth: lW * remoteLocalWidthRatio,
thumbWidth: removeVideoWidth,
thumbHeight: h
}
};
@ -407,10 +424,15 @@ const Filmstrip = {
}));
}
promises.push(new Promise((resolve) => {
this.filmstrip.animate({
// adds 2 px because of small video 1px border
height: remote.thumbHeight + 2
}, this._getAnimateOptions(animate, resolve));
// Let CSS take care of height in vertical filmstrip mode.
if (interfaceConfig.VERTICAL_FILMSTRIP) {
resolve();
} else {
this.filmstrip.animate({
// adds 2 px because of small video 1px border
height: remote.thumbHeight + 2
}, this._getAnimateOptions(animate, resolve));
}
}));
promises.push(new Promise(() => {

View File

@ -91,7 +91,8 @@ RemoteVideo.prototype._initPopupMenu = function (popupMenuElement) {
content: popupMenuElement.outerHTML,
skin: "black",
hasArrow: false,
onBeforePosition: el => APP.translation.translateElement(el)
onBeforePosition: el => APP.translation.translateElement(el),
position: interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top'
};
let element = $("#" + this.videoSpanId + " .remotevideomenu");
this.popover = new JitsiPopover(element, options);