Merge pull request #1110 from jitsi/filmstrip-button-editions
Filmstrip button editions
This commit is contained in:
commit
101c413a3c
|
@ -0,0 +1,120 @@
|
|||
%align-right {
|
||||
@include flex();
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.filmstrip {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
padding: 10px 5px;
|
||||
@extend %align-right;
|
||||
|
||||
&__toolbar {
|
||||
@include flex();
|
||||
flex-direction: column-reverse;
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
z-index: 1; // Set z-index to make element visible
|
||||
width: 17px;
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
background: transparent;
|
||||
opacity: 0.7;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
-webkit-appearance: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__videos {
|
||||
@extend %align-right;
|
||||
position:relative;
|
||||
height:196px;
|
||||
padding: 0;
|
||||
bottom: 0;
|
||||
width:auto;
|
||||
border: 2px solid transparent;
|
||||
z-index: 5;
|
||||
transition: bottom 2s;
|
||||
overflow: visible !important;
|
||||
font-size: 0pt; /*!!!Removes the gap between the local video container and the remote videos.*/
|
||||
|
||||
&.hidden {
|
||||
bottom: -196px;
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
display: none;
|
||||
position: relative;
|
||||
background-size: contain;
|
||||
border: 2px solid transparent;
|
||||
border-radius:1px;
|
||||
margin: 0 $thumbnailVideoMargin;
|
||||
|
||||
&.videoContainerFocused, &:hover {
|
||||
cursor: hand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focused video thumbnail.
|
||||
*/
|
||||
&.videoContainerFocused {
|
||||
transition-duration: 0.5s;
|
||||
-webkit-transition-duration: 0.5s;
|
||||
-webkit-animation-name: greyPulse;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
border: 2px solid $videoThumbnailSelected !important;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailSelected,
|
||||
0 0 3px $videoThumbnailSelected !important;
|
||||
}
|
||||
|
||||
.remotevideomenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hovered video thumbnail.
|
||||
*/
|
||||
&:hover {
|
||||
cursor: hand;
|
||||
border: 2px solid $videoThumbnailHovered;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailHovered,
|
||||
0 0 3px $videoThumbnailHovered;
|
||||
|
||||
.remotevideomenu {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
/* With TemasysWebRTC plugin <object/> element is used
|
||||
instead of <video/> */
|
||||
& > video,
|
||||
& > object {
|
||||
cursor: hand;
|
||||
border-radius:1px;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,7 +93,7 @@
|
|||
|
||||
#toast-container.notification-bottom-right {
|
||||
bottom: 135px;
|
||||
right: 13px;
|
||||
right: 28px;
|
||||
}
|
||||
|
||||
#toast-container * {
|
||||
|
|
|
@ -12,34 +12,6 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#remoteVideos {
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
position:absolute;
|
||||
text-align:right;
|
||||
height:196px;
|
||||
padding: 10px 10px 17px 5px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width:auto;
|
||||
border: 2px solid transparent;
|
||||
z-index: 5;
|
||||
transition: bottom 2s;
|
||||
overflow: visible !important;
|
||||
font-size: 0pt; /*!!!Removes the gap between the local video container and the remote videos.*/
|
||||
}
|
||||
|
||||
#remotevideos.hidden {
|
||||
bottom: -196px;
|
||||
}
|
||||
|
||||
.videocontainer {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
@ -52,15 +24,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
#remoteVideos .videocontainer {
|
||||
display: none;
|
||||
position: relative;
|
||||
background-size: contain;
|
||||
border: 2px solid transparent;
|
||||
border-radius:1px;
|
||||
margin: 0 $thumbnailVideoMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* The toolbar of the video thumbnail.
|
||||
*/
|
||||
|
@ -96,60 +59,10 @@
|
|||
z-index: 2;
|
||||
}
|
||||
|
||||
#remoteVideos .videocontainer.videoContainerFocused,
|
||||
#remoteVideos .videocontainer:hover {
|
||||
cursor: hand;
|
||||
}
|
||||
/**
|
||||
* Focused video thumbnail.
|
||||
*/
|
||||
#remoteVideos .videocontainer.videoContainerFocused {
|
||||
transition-duration: 0.5s;
|
||||
-webkit-transition-duration: 0.5s;
|
||||
-webkit-animation-name: greyPulse;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
border: 2px solid $videoThumbnailSelected !important;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailSelected,
|
||||
0 0 3px $videoThumbnailSelected !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hovered video thumbnail.
|
||||
*/
|
||||
#remoteVideos .videocontainer {
|
||||
.remotevideomenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show/hide items for hover event here
|
||||
*/
|
||||
&:hover {
|
||||
cursor: hand;
|
||||
border: 2px solid $videoThumbnailHovered;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailHovered,
|
||||
0 0 3px $videoThumbnailHovered;
|
||||
.remotevideomenu {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#localVideoWrapper {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
/* With TemasysWebRTC plugin <object/> element is used
|
||||
instead of <video/> */
|
||||
#remoteVideos .videocontainer>video,
|
||||
#remoteVideos .videocontainer>object {
|
||||
cursor: hand;
|
||||
border-radius:1px;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flipVideoX {
|
||||
transform: scale(-1, 1);
|
||||
-moz-transform: scale(-1, 1);
|
||||
|
@ -618,39 +531,4 @@
|
|||
|
||||
.moveToCorner + .moveToCorner {
|
||||
right: 80px;
|
||||
}
|
||||
|
||||
.filmstripToolbar {
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
bottom: 20px;
|
||||
z-index: 6;
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
background: transparent;
|
||||
opacity: 0.7;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0 1px;
|
||||
border: none;
|
||||
|
||||
-webkit-appearance: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filmstripToolbar + #remoteVideos {
|
||||
padding-right: 24px;
|
||||
}
|
|
@ -63,5 +63,6 @@
|
|||
@import 'aui-components/dropdown';
|
||||
@import '404';
|
||||
@import 'policy';
|
||||
@import 'filmstrip';
|
||||
|
||||
/* Modules END */
|
||||
|
|
28
index.html
28
index.html
|
@ -166,21 +166,23 @@
|
|||
<img id="recordingSpinner" class="recordingSpinner" src="images/spin.svg"></img>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="remoteVideos">
|
||||
<span id="localVideoContainer" class="videocontainer videocontainer_small">
|
||||
<div class="videocontainer__background"></div>
|
||||
<span id="localVideoWrapper">
|
||||
<!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
|
||||
<div class="filmstrip">
|
||||
<div class="filmstrip__videos" id="remoteVideos">
|
||||
<span id="localVideoContainer" class="videocontainer videocontainer_small">
|
||||
<div class="videocontainer__background"></div>
|
||||
<span id="localVideoWrapper">
|
||||
<!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
|
||||
</span>
|
||||
<audio id="localAudio" autoplay muted></audio>
|
||||
<div class="videocontainer__toolbar"></div>
|
||||
<div class="videocontainer__toptoolbar"></div>
|
||||
<div class="videocontainer__hoverOverlay"></div>
|
||||
</span>
|
||||
<audio id="localAudio" autoplay muted></audio>
|
||||
<div class="videocontainer__toolbar"></div>
|
||||
<div class="videocontainer__toptoolbar"></div>
|
||||
<div class="videocontainer__hoverOverlay"></div>
|
||||
</span>
|
||||
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
||||
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
||||
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
||||
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
||||
|
|
|
@ -10,48 +10,72 @@ const FilmStrip = {
|
|||
* emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILM_STRIP}).
|
||||
*/
|
||||
init (eventEmitter) {
|
||||
this.iconMenuDownClassName = 'icon-menu-down';
|
||||
this.iconMenuUpClassName = 'icon-menu-up';
|
||||
this.filmStrip = $('#remoteVideos');
|
||||
this.eventEmitter = eventEmitter;
|
||||
this.filmStripIsVisible = true;
|
||||
this.renderFilmstripToolbar();
|
||||
this.activateHideButton();
|
||||
this._initFilmStripToolbar();
|
||||
this.registerListeners();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the filmstrip toolbar
|
||||
*/
|
||||
_initFilmStripToolbar() {
|
||||
let toolbar = this._generateFilmStripToolbar();
|
||||
let container = document.querySelector('.filmstrip');
|
||||
|
||||
UIUtil.prependChild(container, toolbar);
|
||||
|
||||
let iconSelector = '#hideVideoToolbar i';
|
||||
this.toggleFilmStripIcon = document.querySelector(iconSelector);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates HTML layout for filmstrip toolbar
|
||||
* @returns {HTMLElement}
|
||||
* @private
|
||||
*/
|
||||
_generateFilmStripToolbar() {
|
||||
let container = document.createElement('div');
|
||||
let isVisible = this.isFilmStripVisible();
|
||||
container.className = 'filmstrip__toolbar';
|
||||
|
||||
container.innerHTML = `
|
||||
<button id="hideVideoToolbar">
|
||||
<i class="icon-menu-${isVisible ? 'down' : 'up'}">
|
||||
</i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach 'click' listener to "hide filmstrip" button
|
||||
*/
|
||||
activateHideButton () {
|
||||
$('#videospace').on('click', '#hideVideoToolbar', () => {
|
||||
var icon = document.querySelector('#hideVideoToolbar i');
|
||||
|
||||
this.filmStripIsVisible = !this.filmStripIsVisible;
|
||||
this.toggleFilmStrip(this.filmStripIsVisible);
|
||||
|
||||
icon.classList.remove(
|
||||
this.filmStripIsVisible ? 'icon-menu-up' : 'icon-menu-down');
|
||||
icon.classList.add(
|
||||
this.filmStripIsVisible ? 'icon-menu-down' : 'icon-menu-up');
|
||||
});
|
||||
registerListeners() {
|
||||
let toggleFilmstripMethod = this.toggleFilmStrip.bind(this);
|
||||
let selector = '#hideVideoToolbar';
|
||||
$('#videospace').on('click', selector, toggleFilmstripMethod);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows toolbar on the right of the filmstrip
|
||||
* Changes classes of icon for showing down state
|
||||
*/
|
||||
renderFilmstripToolbar () {
|
||||
// create toolbar
|
||||
var container = document.createElement('div');
|
||||
container.className = 'filmstripToolbar';
|
||||
showMenuDownIcon() {
|
||||
let icon = this.toggleFilmStripIcon;
|
||||
icon.classList.add(this.iconMenuDownClassName);
|
||||
icon.classList.remove(this.iconMenuUpClassName);
|
||||
},
|
||||
|
||||
container.innerHTML = `
|
||||
<button id="hideVideoToolbar">
|
||||
<i class="icon-menu-${this.filmStripIsVisible ? 'down' : 'up'}">
|
||||
</i>
|
||||
</button>
|
||||
`;
|
||||
|
||||
// show toolbar
|
||||
document.querySelector('#videospace')
|
||||
.insertBefore(container, document.querySelector('#remoteVideos'));
|
||||
/**
|
||||
* Changes classes of icon for showing up state
|
||||
*/
|
||||
showMenuUpIcon() {
|
||||
let icon = this.toggleFilmStripIcon;
|
||||
icon.classList.add(this.iconMenuUpClassName);
|
||||
icon.classList.remove(this.iconMenuDownClassName);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -62,14 +86,22 @@ const FilmStrip = {
|
|||
* (i.e. toggled); otherwise, the visibility will be set to the specified
|
||||
* value.
|
||||
*/
|
||||
toggleFilmStrip (visible) {
|
||||
if (typeof visible === 'boolean'
|
||||
&& this.isFilmStripVisible() == visible) {
|
||||
toggleFilmStrip(visible) {
|
||||
let isVisibleDefined = typeof visible === 'boolean';
|
||||
if (!isVisibleDefined) {
|
||||
visible = this.isFilmStripVisible();
|
||||
} else if (this.isFilmStripVisible() === visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.filmStrip.toggleClass("hidden");
|
||||
|
||||
if (!visible) {
|
||||
this.showMenuDownIcon();
|
||||
} else {
|
||||
this.showMenuUpIcon();
|
||||
}
|
||||
|
||||
// Emit/fire UIEvents.TOGGLED_FILM_STRIP.
|
||||
var eventEmitter = this.eventEmitter;
|
||||
if (eventEmitter) {
|
||||
|
@ -79,18 +111,26 @@ const FilmStrip = {
|
|||
}
|
||||
},
|
||||
|
||||
isFilmStripVisible () {
|
||||
/**
|
||||
* Shows if filmstrip is visible
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isFilmStripVisible() {
|
||||
return !this.filmStrip.hasClass('hidden');
|
||||
},
|
||||
|
||||
setupFilmStripOnly () {
|
||||
setupFilmStripOnly() {
|
||||
this.filmStrip.css({
|
||||
padding: "0px 0px 18px 0px",
|
||||
right: 0
|
||||
});
|
||||
},
|
||||
|
||||
getFilmStripHeight () {
|
||||
/**
|
||||
* Returns the height of filmstrip
|
||||
* @returns {number} height
|
||||
*/
|
||||
getFilmStripHeight() {
|
||||
if (this.isFilmStripVisible()) {
|
||||
return this.filmStrip.outerHeight();
|
||||
} else {
|
||||
|
@ -98,12 +138,20 @@ const FilmStrip = {
|
|||
}
|
||||
},
|
||||
|
||||
getFilmStripWidth () {
|
||||
/**
|
||||
* Returns the width of filmstip
|
||||
* @returns {number} width
|
||||
*/
|
||||
getFilmStripWidth() {
|
||||
return this.filmStrip.innerWidth()
|
||||
- parseInt(this.filmStrip.css('paddingLeft'), 10)
|
||||
- parseInt(this.filmStrip.css('paddingRight'), 10);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the size for thumbnails: local and remote one
|
||||
* @returns {*|{localVideo, remoteVideo}}
|
||||
*/
|
||||
calculateThumbnailSize() {
|
||||
let availableSizes = this.calculateAvailableSize();
|
||||
let width = availableSizes.availableWidth;
|
||||
|
@ -115,7 +163,7 @@ const FilmStrip = {
|
|||
/**
|
||||
* Normalizes local and remote thumbnail ratios
|
||||
*/
|
||||
normalizeThumbnailRatio () {
|
||||
normalizeThumbnailRatio() {
|
||||
let remoteHeightRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_HEIGHT;
|
||||
let remoteWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO_WIDTH;
|
||||
|
||||
|
@ -146,6 +194,11 @@ const FilmStrip = {
|
|||
return { localRatio, remoteRatio };
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates available size for one thumbnail according to
|
||||
* the current window size
|
||||
* @returns {{availableWidth: number, availableHeight: number}}
|
||||
*/
|
||||
calculateAvailableSize() {
|
||||
let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
|
||||
let thumbs = this.getThumbs(true);
|
||||
|
@ -221,6 +274,13 @@ const FilmStrip = {
|
|||
return { availableWidth, availableHeight };
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes the available size for thumbnail and calculates
|
||||
* final size of thumbnails
|
||||
* @param availableWidth
|
||||
* @param availableHeight
|
||||
* @returns {{localVideo, remoteVideo}}
|
||||
*/
|
||||
calculateThumbnailSizeFromAvailable(availableWidth, availableHeight) {
|
||||
let { localRatio, remoteRatio } = this.normalizeThumbnailRatio();
|
||||
let { remoteThumbs } = this.getThumbs(true);
|
||||
|
@ -251,7 +311,15 @@ const FilmStrip = {
|
|||
};
|
||||
},
|
||||
|
||||
resizeThumbnails (local, remote,
|
||||
/**
|
||||
* Resizes thumbnails
|
||||
* @param local
|
||||
* @param remote
|
||||
* @param animate
|
||||
* @param forceUpdate
|
||||
* @returns {Promise}
|
||||
*/
|
||||
resizeThumbnails(local, remote,
|
||||
animate = false, forceUpdate = false) {
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
@ -289,7 +357,12 @@ const FilmStrip = {
|
|||
});
|
||||
},
|
||||
|
||||
getThumbs (only_visible = false) {
|
||||
/**
|
||||
* Returns thumbnails of the filmstrip
|
||||
* @param only_visible
|
||||
* @returns {object} thumbnails
|
||||
*/
|
||||
getThumbs(only_visible = false) {
|
||||
let selector = 'span';
|
||||
if (only_visible) {
|
||||
selector += ':visible';
|
||||
|
|
Loading…
Reference in New Issue