Settings re-design

This commit is contained in:
yanas 2016-09-11 16:54:32 -05:00
parent 50e803f1a0
commit f811410b45
20 changed files with 792 additions and 309 deletions

View File

@ -6,8 +6,8 @@
html, body{
margin:0px;
height:100%;
color: #424242;
font-size: 14px;
color: $defaultColor;
font-size: 12px;
font-weight: 400;
background: #000000;
overflow: hidden;
@ -29,25 +29,17 @@ input[type='text'], input[type='password'], textarea {
-webkit-user-select: text;
user-select: text;
display: inline-block;
font-size: 14px;
padding: 5px;
background: #f3f3f3;
border-radius: 3px;
font-weight: 100;
line-height: 20px;
height: 40px;
color: #333;
color: $defaultDarkColor;
border-radius: $borderRadius;
line-height: 32px;
height: 32px;
text-align: left;
border:1px solid #ACD8F0;
border:1px solid $inputBorderColor;
outline: none; /* removes the default outline */
resize: none; /* prevents the user-resizing, adjust to taste */
}
input[type='text'], input[type='password'], textarea:focus {
box-shadow: inset 0 0 3px 2px #ACD8F0; /* provides a more style-able
replacement to the outline */
}
textarea {
overflow: hidden;
word-wrap: break-word;
@ -58,28 +50,33 @@ button.no-icon {
padding: 0 1em;
}
button {
border: none;
height: 35px;
padding: 0 1em 0 2em;
position: relative;
border-radius: 1px;
font-weight: bold;
color: #fff;
line-height: 35px;
background: #2c8ad2;
}
button, input, select, textarea {
margin: 0;
vertical-align: baseline;
color: $defaultDarkColor;
background: $inputLightBackground;
font-size: 12px;
border: none;
box-shadow: none;
outline: none;
}
button, input[type="button"], input[type="reset"], input[type="submit"] {
button, select, input[type="button"],
input[type="reset"], input[type="submit"] {
height: 32px;
line-height: 32px;
padding-left: 4px;
padding-right: 4px;
cursor: pointer;
-webkit-appearance: button;
}
button {
color: #FFF;
background-color: $buttonBackground !important;
border-radius: $borderRadius;
}
button,
form {
display: block;
}
@ -137,32 +134,6 @@ form {
z-index: 100;
}
#toast-container.notification-bottom-right {
bottom: 140px;
right: 5px;
}
#toast-container.notification-bottom-right-center {
right: 205px;
}
#toast-container .toast-info {
-webkit-box-shadow: none;
box-shadow: none;
}
.toast-close-button {
right: -7px;
top: -19px;
}
#toast-container .toast-info {
background-color: black;
border: 1px solid #3a3a3a;
width: 220px;
padding: 10px 10px 10px 50px;
}
.connected {
color: #21B9FC;
font-size: 12px;
@ -173,18 +144,6 @@ form {
font-size: 12px;
}
.toast-close-button:hover,
.toast-close-button:focus {
color: #ffffff;
opacity: 1;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
filter: alpha(opacity=100);
}
.toast-message .nickname {
font-weight: bold;
}
/**
* Hides an element.
*/

View File

@ -0,0 +1,31 @@
.settingsContent {
display: flex;
display: -webkit-flex;
#localVideoPreview {
width: 50%;
align-self: baseline;
}
.deviceSelection {
display: flex;
display: -webkit-flex;
-webkit-flex: 1;
flex: 1;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: left;
margin-left: 10px;
.device {
display: flex;
margin-bottom: 5px;
select {
flex: 1;
margin_right: 5px;
}
}
}
}

View File

@ -55,7 +55,7 @@ div.jqi .jqibuttons{
div.jqi .jqibuttons button{
margin: 0;
padding: 5px 20px;
background-color: transparent;
background-color: transparent !important;
font-weight: normal;
border: none;
border-left: solid 1px #e4e4e4;

View File

@ -1,77 +0,0 @@
#settings_container input, select {
margin-top: 10px;
margin-left: 10%;
width: 80%;
font-size: 14px;
background: #3a3a3a;
border: none;
box-shadow: none;
color: #a7a7a7;
}
#settings_container .arrow-up {
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid #3a3a3a;
position: relative;
top: 10px;
margin-left: auto;
margin-right: auto;
}
#settings_container #avatar {
width: 24%;
left: 38%;
border-radius: 25px;
position: relative;
}
#languages_selectbox {
height: 40px;
cursor: pointer;
}
#startMutedOptions,
#followMeOptions {
padding-left: 10%;
text-indent: -10%;
margin-top: 10px;
display: none; /* hide by default */
/* clearfix */
overflow: auto;
zoom: 1;
}
#startAudioMuted,
#startVideoMuted,
#followMeCheckBox {
width: 13px !important;
}
.startMutedLabel,
.followMeLabel {
width: 94%;
float: left;
cursor: pointer;
}
#devicesOptions {
display: none;
margin-top: 10px;
}
#devicesOptions label {
display: block;
margin-top: 15px;
}
#devicesOptions span {
padding-left: 10%;
}
#devicesOptions select {
height: 40px;
cursor: pointer;
}

View File

@ -0,0 +1,114 @@
/**
* Toolbar side panel main container element.
*/
#sideToolbarContainer {
display: inline-block;
position:absolute;
top: 0px;
left: $defaultToolbarSize;
width: 0%;
height: 100%;
max-width: 200px;
background-color: rgba(0,0,0,0.8);
z-index: 800;
overflow: hidden;
/**
* Labels inside the side panel.
*/
label {
color: $defaultSemiDarkColor;
}
/**
* Form elements and blocks.
*/
input, label, select, button, a, .sideToolbarBlock {
display: inline-block;
margin-top: 15px;
margin-left: 10%;
width: 80%;
}
/**
* Specify colors for edit elements.
*/
select, input[type="button"], input[type="text"],
input[type="reset"], input[type="submit"] {
color: $defaultColor;
background: $inputBackground;
border: none;
}
/**
* Specify styling of elements inside a block.
*/
.sideToolbarBlock {
input, label, button, a, select {
margin-top: 5px;
margin-left: 0;
width: 100%;
}
.startMutedLabel,
.followMeLabel {
display: inline;
margin-top: 0;
}
}
/**
* Inner container, for example contact list, settings or profile.
*/
.sideToolbarContainer__inner {
display: none;
width: 200px;
color: #FFF;
/**
* Titles and subtitles of inner containers.
*/
> div.title,
div.subTitle {
color: $defaultColor !important;
text-align: left;
margin: 10px 0px 10px 0px;
padding: 5px 10px 5px 10px;
}
/**
* Main title size.
*/
> div.title {
font-size: 16px;
}
/**
* Subtitle specific properties.
*/
> div.subTitle {
font-size: 12px;
background: $inputSemiBackground !important;
margin-top: 20px !important;
margin-bottom: 8px !important;
}
/**
* First element after a title.
*/
.first {
margin-top: 0px !important;
}
}
}
#device_settings {
width : auto !important;
text-align: center;
}
#startAudioMuted,
#startVideoMuted,
#followMeCheckBox {
width: 13px !important;
}

View File

@ -19,32 +19,42 @@
.toast-message label {
color: #ffffff;
}
.toast-message .nickname {
font-weight: bold;
}
.toast-message a:hover {
color: #cccccc;
text-decoration: none;
}
.toast-close-button {
position: relative;
right: -0.3em;
top: -0.3em;
float: right;
font-size: 20px;
font-size: 15px;
height: 15px;
width: 15px;
font-weight: bold;
color: #ffffff;
background: transparent !important;
-webkit-text-shadow: 0 1px 0 #ffffff;
text-shadow: 0 1px 0 #ffffff;
opacity: 0.8;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
filter: alpha(opacity=80);
}
.toast-close-button:hover,
.toast-close-button:focus {
color: #000000;
color: #ffffff;
text-decoration: none;
cursor: pointer;
opacity: 0.4;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
filter: alpha(opacity=40);
opacity: 1;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
filter: alpha(opacity=100);
}
/*Additional properties for button version
iOS requires the button element instead of an anchor tag.
@ -173,4 +183,30 @@ button.toast-close-button {
padding: 15px 15px 15px 15px;
width: 25em;
}
}
#toast-container.notification-bottom-right {
bottom: 140px;
right: 5px;
}
#toast-container.notification-bottom-right-center {
right: 205px;
}
#toast-container .toast-info {
-webkit-box-shadow: none;
box-shadow: none;
}
.toast-close-button {
right: -7px;
top: -19px;
}
#toast-container .toast-info {
background-color: black;
border: 1px solid #3a3a3a;
width: 220px;
padding: 10px 10px 10px 50px;
}

View File

@ -74,34 +74,8 @@
-webkit-transform: translateX(-100%);
}
#sideToolbarContainer {
display: inline-block;
position:absolute;
top: 0px;
left: $defaultToolbarSize;
width: 0%;
height: 100%;
max-width: 200px;
background-color: rgba(0,0,0,0.8);
z-index: 800;
overflow: hidden;
.sideToolbarContainer__inner {
display: none;
width: 200px;
color: #FFF;
> div.title {
text-align: left;
padding: 10px;
margin: 2px;
font-size: 12pt;
}
}
}
#toolbar_button_hangup {
color: #ff0000;
color: #BF2117;
font-size: 2.2em !important;
}

View File

@ -9,7 +9,22 @@ $baseFontFamily: 'open_sanslight', 'Helvetica Neue', Helvetica, Arial, sans-seri
$defaultToolbarSize: 50px;
/**
* Miscellaneous.
* Color variables.
*/
$defaultColor: #ECEEF1;
$defaultSemiDarkColor: #8E96A8;
$defaultDarkColor: #172B4D;
$defaultBackground: #091E42;
$toolbarSelectBackground: rgba(0, 0, 0, 0.6);
$inputBackground: rgba(94, 108, 132, .5);
$inputSemiBackground: rgba(94, 108, 132, .8);
$inputLightBackground: #E5E8EC;
$inputBorderColor: #E5E8EC;
$buttonBackground: #0074E0;
/**
* Misc.
*/
$borderRadius: 4px;

View File

@ -1,4 +1,3 @@
#disable_welcome {
display:none;
}
@ -59,6 +58,7 @@
font-size: 18px;
font-weight: 500;
padding-left: 20px;
color: $defaultDarkColor;
}
#enter_room_field {

View File

@ -34,9 +34,10 @@
@import 'contact_list';
@import 'chat';
@import 'welcome_page';
@import 'settingsmenu';
@import 'feedback';
@import 'toolbars';
@import 'side_toolbar_container';
@import 'device_settings_dialog';
@import 'feedback';
@import 'jquery.contextMenu';
@import 'keyboard-shortcuts';

View File

@ -100,24 +100,11 @@
<div id="notice" class="notice" style="display: none">
<span id="noticeText" class="noticeText"></span>
</div>
<span id="mainToolbar" class="toolbar">
<a class="button icon-share-desktop first" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleDesktopSharingPopover" content="Share screen" data-i18n="[content]toolbar.sharescreen" style="display: none"></a>
<a class="button icon-microphone" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
<ul id="micMutedPopup" class="loginmenu">
<li data-i18n="[html]toolbar.micMutedPopup"></li>
</ul>
<ul id="unableToUnmutePopup" class="loginmenu">
<li data-i18n="[html]toolbar.unableToUnmutePopup"></li>
</ul>
</a>
<a class="button icon-hangup" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" data-i18n="[content]toolbar.hangup"></a>
<a class="button icon-camera" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" data-i18n="[content]toolbar.videomute" content="Start / stop camera"></a>
<a class="button icon-full-screen last" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen" data-i18n="[content]toolbar.fullscreen"></a>
</span>
<span id="mainToolbar" class="toolbar"></span>
</div>
<div id="subject" class="hide"></div>
<div id="extendedToolbar" class="toolbar">
<a class="button" data-container="body" data-placement="right" data-i18n="[content]toolbar.profile" content="Edit your profile">
<a class="button" id="toolbar_button_profile" data-container="body" data-placement="right" data-i18n="[content]toolbar.profile" content="Edit your profile">
<img id="avatar" src="images/avatar2.png"/>
</a>
<span id="authentication" class="authentication" style="display: none">
@ -154,6 +141,17 @@
<a class="button icon-filmstrip" id="toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="right" data-i18n="[content]toolbar.filmstrip" content="Show / hide videos"></a>
<a class="button fa fa-heart" id="feedbackButton" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[content]feedback"></a>
<div id="sideToolbarContainer">
<div id="profile_container" class="sideToolbarContainer__inner">
<div class="title" data-i18n="profile.title"></div>
<div class="sideToolbarBlock first">
<label class="first" data-i18n="profile.setDisplayNameLabel"></label>
<input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
</div>
<div class="sideToolbarBlock">
<label data-i18n="profile.setEmailLabel"></label>
<input type="text" id="setEmail" placeholder="Enter e-mail">
</div>
</div>
<div id="chat_container" class="sideToolbarContainer__inner">
<div id="nickname">
<span data-i18n="chat.nickname.title"></span>
@ -177,39 +175,36 @@
</div>
<div id="settings_container" class="sideToolbarContainer__inner">
<div class="title" data-i18n="settings.title"></div>
<div class="arrow-up"></div>
<input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
<input type="text" id="setEmail" placeholder="E-Mail">
<select id="languages_selectbox"></select>
<div id = "startMutedOptions">
<label class = "startMutedLabel">
<input type="checkbox" id="startAudioMuted">
<span data-i18n="settings.startAudioMuted"></span>
</label>
<label class = "startMutedLabel">
<input type="checkbox" id="startVideoMuted">
<span data-i18n="settings.startVideoMuted"></span>
</label>
</div>
<select class="first" id="languages_selectbox"></select>
<div class="subTitle" data-i18n="settings.audioVideo"></div>
<div id="devicesOptions">
<label className="devicesOptionsLabel">
<span data-i18n="settings.selectCamera"></span>
<div class="sideToolbarBlock first">
<label class="first" data-i18n="settings.selectCamera"></label>
<select id="selectCamera"></select>
</label>
<label className="devicesOptionsLabel">
<span data-i18n="settings.selectMic"></span>
<select id="selectMic"></select>
</label>
<label className="devicesOptionsLabel">
<span data-i18n="settings.selectAudioOutput"></span>
<select id="selectAudioOutput"></select>
</label>
</div>
<div class="sideToolbarBlock">
<label data-i18n="settings.selectMic"></label>
<select id="selectMic"></select>
</div>
<div class="sideToolbarBlock">
<label data-i18n="settings.selectAudioOutput"></label>
<select id="selectAudioOutput"></select>
</div>
</div>
<div id="followMeOptions">
<label class = "followMeLabel">
<input type="checkbox" id="followMeCheckBox">
<span data-i18n="settings.followMe"></span>
</label>
<div class="subTitle" data-i18n="settings.moderator"></div>
<div id = "startMutedOptions">
<div class="sideToolbarBlock first">
<input type="checkbox" id="startAudioMuted">
<label class="startMutedLabel" for="startAudioMuted" data-i18n="settings.startAudioMuted"></label>
</div>
<div class="sideToolbarBlock">
<input type="checkbox" id="startVideoMuted">
<label class="startMutedLabel" for="startVideoMuted" data-i18n="settings.startVideoMuted"></label>
</div>
</div>
<div id="followMeOptions" class="sideToolbarBlock">
<input type="checkbox" id="followMeCheckBox">
<label class="followMeLabel" for="followMeCheckBox" data-i18n="settings.followMe"></label>
</div>
<a id="downloadlog" data-container="body" data-toggle="popover" data-placement="right" data-i18n="[data-content]downloadlogs" ><i class="fa fa-cloud-download"></i></a>
</div>

View File

@ -16,6 +16,7 @@ var interfaceConfig = {
INVITATION_POWERED_BY: true,
// the toolbar buttons line is intentionally left in one line, to be able
// to easily override values or remove them using regex
MAIN_TOOLBAR_BUTTONS: ['microphone', 'camera', 'desktop', 'fullscreen', 'hangup'], // jshint ignore:line
TOOLBAR_BUTTONS: ['authentication', 'microphone', 'camera', 'desktop', 'recording', 'security', 'invite', 'chat', 'etherpad', 'sharedvideo', 'fullscreen', 'sip', 'dialpad', 'settings', 'hangup', 'filmstrip', 'contacts'], // jshint ignore:line
// Determines how the video would fit the screen. 'both' would fit the whole
// screen, 'height' would fit the original video height to the height of the

View File

@ -1,5 +1,5 @@
{
"contactlist": "On Call (__participants__)",
"contactlist": "ON CALL (__participants__)",
"connectionsettings": "Connection Settings",
"poweredby": "powered by",
"downloadlogs": "Download logs",
@ -109,17 +109,27 @@
},
"settings":
{
"title": "Settings",
"title": "SETTINGS",
"update": "Update",
"name": "Name",
"startAudioMuted": "Start without audio",
"startVideoMuted": "Start without video",
"startAudioMuted": "Everyone starts muted",
"startVideoMuted": "Everyone starts hidden",
"selectCamera": "Select camera",
"selectMic": "Select microphone",
"selectAudioOutput": "Select audio output",
"followMe": "Enable follow me",
"followMe": "Everyone follows me",
"noDevice": "None",
"noPermission": "Permission to use device is not granted"
"noPermission": "Permission to use device is not granted",
"cameraAndMic": "Camera and microphone",
"moderator": "MODERATOR",
"password": "SET PASSWORD",
"audioVideo": "AUDIO / VIDEO",
"setPasswordLabel": "Lock your room with a password."
},
"profile": {
"title": "PROFILE",
"setDisplayNameLabel": "Set your display name",
"setEmailLabel": "Set your gravatar email"
},
"videothumbnail":
{
@ -221,18 +231,18 @@
"Remove": "Remove",
"passwordMsg": "Set a password to lock your room",
"Invite": "Invite",
"shareLink": "Share this link with everyone you want to invite",
"shareLink": "Copy and share this link",
"settings1": "Configure your conference",
"settings2": "Participants join muted",
"settings3": "Require nicknames<br/><br/>Set a password to lock your room:",
"yourPassword": "your password",
"yourPassword": "Enter new password",
"Back": "Back",
"serviceUnavailable": "Service unavailable",
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
"Yes": "Yes",
"reservationError": "Reservation system error",
"reservationErrorMsg": "Error code: __code__, message: __msg__",
"password": "password",
"password": "Enter password",
"userPassword": "user password",
"token": "token",
"tokenAuthFailed": "Failed to authenticate with XMPP server: invalid token",

View File

@ -19,6 +19,7 @@ import GumPermissionsOverlay from './gum_overlay/UserMediaPermissionsGuidanceOve
import VideoLayout from "./videolayout/VideoLayout";
import FilmStrip from "./videolayout/FilmStrip";
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
import Profile from "./side_pannels/profile/Profile";
import Settings from "./../settings/Settings";
import { reload } from '../util/helpers';
import RingOverlay from "./ring_overlay/RingOverlay";
@ -140,7 +141,7 @@ function setupToolbars() {
* (a.k.a. presentation mode in Chrome).
* @see https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
*/
function toggleFullScreen () {
UI.toggleFullScreen = function() {
// alternative standard method
let isNotFullScreen = !document.fullscreenElement &&
!document.mozFullScreenElement && // current working methods
@ -169,7 +170,7 @@ function toggleFullScreen () {
document.webkitExitFullscreen();
}
}
}
};
/**
* Notify user that server has shut down.
@ -251,7 +252,7 @@ UI.changeDisplayName = function (id, displayName) {
VideoLayout.onDisplayNameChanged(id, displayName);
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
SettingsMenu.changeDisplayName(displayName);
Profile.changeDisplayName(displayName);
Chat.setChatConversationMode(!!displayName);
}
};
@ -355,16 +356,20 @@ function registerListeners() {
}
});
UI.addListener(UIEvents.FULLSCREEN_TOGGLE, toggleFullScreen);
UI.addListener(UIEvents.FULLSCREEN_TOGGLE, UI.toggleFullScreen);
UI.addListener(UIEvents.TOGGLE_CHAT, UI.toggleChat);
UI.addListener(UIEvents.TOGGLE_SETTINGS, function () {
SideContainerToggler.toggle("settings_container");
UI.toggleSidePanel("settings_container");
});
UI.addListener(UIEvents.TOGGLE_CONTACT_LIST, UI.toggleContactList);
UI.addListener( UIEvents.TOGGLE_PROFILE, function() {
UI.toggleSidePanel("profile_container");
});
UI.addListener(UIEvents.TOGGLE_FILM_STRIP, UI.handleToggleFilmStrip);
UI.addListener(UIEvents.FOLLOW_ME_ENABLED, function (isEnabled) {
@ -379,6 +384,7 @@ function registerListeners() {
function bindEvents() {
function onResize() {
SideContainerToggler.resize();
VideoLayout.resizeVideoArea();
}
// Resize and reposition videos in full screen mode.
@ -499,6 +505,7 @@ UI.start = function () {
};
SettingsMenu.init(eventEmitter);
Profile.init(eventEmitter);
}
if(APP.tokenData.callee) {
@ -716,16 +723,26 @@ UI.isFilmStripVisible = function () {
* Toggles chat panel.
*/
UI.toggleChat = function () {
SideContainerToggler.toggle("chat_container");
UI.toggleSidePanel("chat_container");
};
/**
* Toggles contact list panel.
*/
UI.toggleContactList = function () {
SideContainerToggler.toggle("contacts_container");
UI.toggleSidePanel("contacts_container");
};
/**
* Toggles the given side panel.
*
* @param {String} sidePanelId the identifier of the side panel to toggle
*/
UI.toggleSidePanel = function (sidePanelId) {
SideContainerToggler.toggle(sidePanelId);
};
/**
* Handle new user display name.
*/
@ -817,6 +834,16 @@ UI.removeListener = function (type, listener) {
eventEmitter.removeListener(type, listener);
};
/**
* Emits the event of given type by specifying the parameters in options.
*
* @param type the type of the event we're emitting
* @param options the parameters for the event
*/
UI.emitEvent = function (type, options) {
eventEmitter.emit(type, options);
};
UI.clickOnVideo = function (videoNumber) {
var remoteVideos = $(".videocontainer:not(#mixedstream)");
if (remoteVideos.length > videoNumber) {
@ -843,7 +870,7 @@ function changeAvatar(id, avatarUrl) {
VideoLayout.changeUserAvatar(id, avatarUrl);
ContactList.changeUserAvatar(id, avatarUrl);
if (APP.conference.isLocalId(id)) {
SettingsMenu.changeAvatar(avatarUrl);
Profile.changeAvatar(avatarUrl);
}
}

View File

@ -0,0 +1,61 @@
/* global APP, $, JitsiMeetJS */
import UIUtil from "../../util/UIUtil";
import UIEvents from "../../../../service/UI/UIEvents";
import languages from "../../../../service/translation/languages";
import Settings from '../../../settings/Settings';
export default {
init (emitter) {
// DISPLAY NAME
function updateDisplayName () {
emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
}
$('#setDisplayName')
.val(Settings.getDisplayName())
.keyup(function (event) {
if (event.keyCode === 13) { // enter
updateDisplayName();
}
})
.focusout(updateDisplayName);
// EMAIL
function updateEmail () {
emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
}
$('#setEmail')
.val(Settings.getEmail())
.keyup(function (event) {
if (event.keyCode === 13) { // enter
updateEmail();
}
}).focusout(updateEmail);
},
/**
* Check if settings menu is visible or not.
* @returns {boolean}
*/
isVisible () {
return UIUtil.isVisible(document.getElementById("profile_container"));
},
/**
* Change user display name in the settings menu.
* @param {string} newDisplayName
*/
changeDisplayName (newDisplayName) {
$('#setDisplayName').val(newDisplayName);
},
/**
* Change user avatar in the settings menu.
* @param {string} avatarUrl url of the new avatar
*/
changeAvatar (avatarUrl) {
$('#avatar').attr('src', avatarUrl);
}
};

View File

@ -0,0 +1,288 @@
/* global APP, $, JitsiMeetJS */
import UIUtil from "../../util/UIUtil";
import UIEvents from "../../../../service/UI/UIEvents";
import languages from "../../../../service/translation/languages";
import Settings from '../../../settings/Settings';
import mediaDeviceHelper from '../../../devices/mediaDeviceHelper';
const RTCUIUtils = JitsiMeetJS.util.RTCUIHelper;
var constructAudioIndicatorHtml = function() {
return '<span>'
+ '<span id="audioLevel0" class="audioLevelDot"></span>'
+ '<span id="audioLevel1" class="audioLevelDot"></span>'
+ '<span id="audioLevel2" class="audioLevelDot"></span>'
+ '<span id="audioLevel3" class="audioLevelDot"></span>'
+ '<span id="audioLevel4" class="audioLevelDot"></span>'
+ '<span id="audioLevel5" class="audioLevelDot"></span>'
+ '<span id="audioLevel6" class="audioLevelDot"></span>'
+ '<span id="audioLevel7" class="audioLevelDot"></span>'
+ '<span id="audioLevel8" class="audioLevelDot"></span>'
+ '<span id="audioLevel9" class="audioLevelDot"></span>'
+ '</span>';
};
var constructMediaSettingsHtml = function() {
return '<div class="settingsContent">'
+ '<video id="localVideoPreview"></video>'
//+ constructAudioIndicatorHtml()
+ '<div class="deviceSelection">'
+ '<span class="device">'
+ '<select id="selectCamera"></select> '
+ '</span>'
+ '<span class="device">'
+ '<select id="selectMic"></select> '
+ '</span>'
+ '<span class="device">'
+ '<select id="selectAudioOutput"></select> '
+ '</span>'
+ '</div>'
+ '</div>';
};
/**
* The callback function corresponding to the openSettingsWindow parameter.
*
* @type {function}
*/
var settingsWindowCallback = null;
/**
* Defines all methods in connection to the Settings dialog.
*/
var SettingsDialog = {
init(eventEmitter) {
this.eventEmitter = eventEmitter;
},
/**
* Generate html select options for available physical devices.
* @param {{ deviceId, label }[]} items available devices
* @param {string} [selectedId] id of selected device
* @param {boolean} permissionGranted if permission to use selected device
* type is granted
* @returns {string}
*/
_generateDevicesOptions(items, selectedId, permissionGranted) {
if (!permissionGranted && items.length) {
return '<option data-i18n="settings.noPermission"></option>';
}
var options = items.map(function (item) {
let attrs = {
value: item.deviceId
};
if (item.deviceId === selectedId) {
attrs.selected = 'selected';
}
let attrsStr = UIUtil.attrsToString(attrs);
return `<option ${attrsStr}>${item.label}</option>`;
});
if (!items.length) {
options.unshift('<option data-i18n="settings.noDevice"></option>');
}
return options.join('');
},
_onLoadMediaSettings() {
let localVideoPreview = document.getElementById("localVideoPreview");
RTCUIUtils.setAutoPlay(localVideoPreview, true);
RTCUIUtils.setVolume(localVideoPreview, 0);
let localVideo = APP.conference.getVideoStream();
if (localVideo)
localVideoPreview = localVideo.attach(localVideoPreview);
this.eventEmitter.addListener(UIEvents.VIDEO_STREAM_CHANGED,
function(newStream)
{
newStream.attach(localVideoPreview);
});
// DEVICES LIST
JitsiMeetJS.mediaDevices.isDeviceListAvailable()
.then((isDeviceListAvailable) => {
if (isDeviceListAvailable &&
JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) {
this._initializeDeviceSelectionSettings();
}
});
APP.UI.eventEmitter.addListener(UIEvents.DEVICE_LIST_CHANGED,
(devices) => {
this._changeDevicesList(devices);
});
},
/**
* Initializes the device list with the current available media devices
* and attaches all listeners needed for device change user
* event handling.
*/
_initializeDeviceSelectionSettings() {
this._changeDevicesList(mediaDeviceHelper.getCurrentMediaDevices());
$('#selectCamera').change(function () {
let cameraDeviceId = $(this).val();
if (cameraDeviceId !== Settings.getCameraDeviceId()) {
this.eventEmitter
.emit(UIEvents.VIDEO_DEVICE_CHANGED, cameraDeviceId);
}
});
$('#selectMic').change(function () {
let micDeviceId = $(this).val();
if (micDeviceId !== Settings.getMicDeviceId()) {
this.eventEmitter
.emit(UIEvents.AUDIO_DEVICE_CHANGED, micDeviceId);
}
});
$('#selectAudioOutput').change(function () {
let audioOutputDeviceId = $(this).val();
if (audioOutputDeviceId !== Settings.getAudioOutputDeviceId()) {
this.eventEmitter.emit(
UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED, audioOutputDeviceId);
}
});
},
/**
* Sets microphone's <select> element to select microphone ID from settings.
*/
setSelectedMicFromSettings () {
$('#selectMic').val(Settings.getMicDeviceId());
},
/**
* Sets camera's <select> element to select camera ID from settings.
*/
setSelectedCameraFromSettings () {
$('#selectCamera').val(Settings.getCameraDeviceId());
},
/**
* Sets audio outputs's <select> element to select audio output ID from
* settings.
*/
setSelectedAudioOutputFromSettings () {
$('#selectAudioOutput').val(Settings.getAudioOutputDeviceId());
},
/**
* Change available cameras/microphones or hide selects completely if
* no devices available.
* @param {{ deviceId, label, kind }[]} devices list of available devices
*/
_changeDevicesList (devices) {
let $selectCamera= $('#selectCamera'),
$selectMic = $('#selectMic'),
$selectAudioOutput = $('#selectAudioOutput'),
$selectAudioOutputParent = $selectAudioOutput.parent();
let audio = devices.audioinput,
video = devices.videoinput,
audioOutput = devices.audiooutput,
selectedAudioDevice = audio.find(
d => d.deviceId === Settings.getMicDeviceId()) || audio[0],
selectedVideoDevice = video.find(
d => d.deviceId === Settings.getCameraDeviceId()) || video[0],
selectedAudioOutputDevice = audioOutput.find(
d => d.deviceId === Settings.getAudioOutputDeviceId()),
videoPermissionGranted =
JitsiMeetJS.mediaDevices.isDevicePermissionGranted('video'),
audioPermissionGranted =
JitsiMeetJS.mediaDevices.isDevicePermissionGranted('audio');
$selectCamera
.html(this._generateDevicesOptions(
video,
selectedVideoDevice ? selectedVideoDevice.deviceId : '',
videoPermissionGranted))
.prop('disabled', !video.length || !videoPermissionGranted);
$selectMic
.html(this._generateDevicesOptions(
audio,
selectedAudioDevice ? selectedAudioDevice.deviceId : '',
audioPermissionGranted))
.prop('disabled', !audio.length || !audioPermissionGranted);
if (JitsiMeetJS.mediaDevices.isDeviceChangeAvailable('output')) {
$selectAudioOutput
.html(this._generateDevicesOptions(
audioOutput,
selectedAudioOutputDevice
? selectedAudioOutputDevice.deviceId
: 'default',
videoPermissionGranted || audioPermissionGranted))
.prop('disabled', !audioOutput.length ||
(!videoPermissionGranted && !audioPermissionGranted));
$selectAudioOutputParent.show();
} else {
$selectAudioOutputParent.hide();
}
$('#devicesOptions').show();
APP.translation.translateElement($('#settings_container option'));
},
/**
* Opens the feedback window.
*/
openSettingsDialog: function (callback) {
settingsWindowCallback = callback;
var htmlString = '<div class="settingsDialog">'
+ constructMediaSettingsHtml()
+ '</div>';
// Defines the different states of the feedback window.
var states = {
mediaSettings: {
title: APP.translation.translateString("settings.title"),
html: htmlString,
persistent: false,
buttons: {},
closeText: '',
//focus: "div[id='stars']",
position: {width: 600}
}
};
const cancelButton
= APP.translation.generateTranslationHTML("dialog.Cancel");
const saveButton
= APP.translation.generateTranslationHTML("dialog.Save");
// Create the settings dialog.
var settingsDialog
= APP.UI.messageHandler.openDialogWithStates(
states,
{
persistent: false,
buttons: [
{title: cancelButton, value: false},
{title: saveButton, value: true}
],
closeText: '',
loaded: this._onLoadMediaSettings.bind(this),
position: {width: 500},
submit: function (e, v, m, f) {
e.preventDefault();
if (!v) {
}
}
}, null);
JitsiMeetJS.analytics.sendEvent('settings.open');
}
};
// Exports the SettingsDialog class.
module.exports = SettingsDialog;

View File

@ -62,34 +62,6 @@ function generateDevicesOptions(items, selectedId, permissionGranted) {
export default {
init (emitter) {
// DISPLAY NAME
function updateDisplayName () {
emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
}
$('#setDisplayName')
.val(Settings.getDisplayName())
.keyup(function (event) {
if (event.keyCode === 13) { // enter
updateDisplayName();
}
})
.focusout(updateDisplayName);
// EMAIL
function updateEmail () {
emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
}
$('#setEmail')
.val(Settings.getEmail())
.keyup(function (event) {
if (event.keyCode === 13) { // enter
updateEmail();
}
}).focusout(updateEmail);
// START MUTED
$("#startMutedOptions").change(function () {
let startAudioMuted = $("#startAudioMuted").is(":checked");
@ -194,22 +166,6 @@ export default {
return UIUtil.isVisible(document.getElementById("settings_container"));
},
/**
* Change user display name in the settings menu.
* @param {string} newDisplayName
*/
changeDisplayName (newDisplayName) {
$('#setDisplayName').val(newDisplayName);
},
/**
* Change user avatar in the settings menu.
* @param {string} avatarUrl url of the new avatar
*/
changeAvatar (avatarUrl) {
$('#avatar').attr('src', avatarUrl);
},
/**
* Sets microphone's <select> element to select microphone ID from settings.
*/
@ -292,4 +248,4 @@ export default {
APP.translation.translateElement($('#settings_container option'));
}
};
};

View File

@ -20,9 +20,13 @@ function openLinkDialog () {
} else {
inviteAttributes = "value=\"" + encodeURI(roomUrl) + "\"";
}
let title = APP.translation.generateTranslationHTML("dialog.shareLink");
APP.UI.messageHandler.openTwoButtonDialog(
"dialog.shareLink", null, null,
`<input id="inviteLinkRef" type="text" ${inviteAttributes} onclick="this.select();" readonly>`,
null, null, null,
'<h2>' + title + '</h2>'
+ '<input id="inviteLinkRef" type="text" '
+ inviteAttributes + ' onclick="this.select();" readonly>',
false, "dialog.Invite",
function (e, v) {
if (v && roomUrl) {
@ -38,7 +42,8 @@ function openLinkDialog () {
document.getElementById('inviteLinkRef').select();
} else {
if (event && event.target) {
$(event.target).find('button[value=true]').prop('disabled', true);
$(event.target).find('button[value=true]')
.prop('disabled', true);
}
}
},
@ -50,6 +55,10 @@ function openLinkDialog () {
}
const buttonHandlers = {
"toolbar_button_profile": function () {
JitsiMeetJS.analytics.sendEvent('toolbar.profile.toggled');
emitter.emit(UIEvents.TOGGLE_PROFILE);
},
"toolbar_button_mute": function () {
let sharedVideoManager = APP.UI.getSharedVideoManager();
@ -116,7 +125,7 @@ const buttonHandlers = {
},
"toolbar_button_fullScreen": function() {
JitsiMeetJS.analytics.sendEvent('toolbar.fullscreen.enabled');
UIUtil.buttonClick("#toolbar_button_fullScreen",
UIUtil.buttonClick("toolbar_button_fullScreen",
"icon-full-screen icon-exit-full-screen");
emitter.emit(UIEvents.FULLSCREEN_TOGGLE);
},
@ -163,45 +172,55 @@ const buttonHandlers = {
emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
}
};
const defaultToolbarButtons = {
'microphone': {
id: '#toolbar_button_mute',
id: 'toolbar_button_mute',
className: "button icon-microphone",
shortcut: 'M',
shortcutAttr: 'mutePopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.audiomute.toggled');
APP.conference.toggleAudioMuted();
},
shortcutDescription: "keyboardShortcuts.mute"
shortcutDescription: "keyboardShortcuts.mute",
content: "Mute / Unmute",
i18n: "[content]toolbar.mute"
},
'camera': {
id: '#toolbar_button_camera',
id: 'toolbar_button_camera',
className: "button icon-camera",
shortcut: 'V',
shortcutAttr: 'toggleVideoPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.videomute.toggled');
APP.conference.toggleVideoMuted();
},
shortcutDescription: "keyboardShortcuts.videoMute"
shortcutDescription: "keyboardShortcuts.videoMute",
content: "Start / stop camera",
i18n: "[content]toolbar.videomute"
},
'desktop': {
id: '#toolbar_button_desktopsharing',
id: 'toolbar_button_desktopsharing',
className: "button icon-share-desktop",
shortcut: 'D',
shortcutAttr: 'toggleDesktopSharingPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.screen.toggled');
APP.conference.toggleScreenSharing();
},
shortcutDescription: "keyboardShortcuts.toggleScreensharing"
shortcutDescription: "keyboardShortcuts.toggleScreensharing",
content: "Share screen",
i18n: "[content]toolbar.sharescreen"
},
'security': {
id: '#toolbar_button_security'
id: 'toolbar_button_security'
},
'invite': {
id: '#toolbar_button_link'
id: 'toolbar_button_link'
},
'chat': {
id: '#toolbar_button_chat',
id: 'toolbar_button_chat',
shortcut: 'C',
shortcutAttr: 'toggleChatPopover',
shortcutFunc: function() {
@ -212,24 +231,41 @@ const defaultToolbarButtons = {
sideContainerId: "chat_container"
},
'contacts': {
id: '#toolbar_contact_list',
id: 'toolbar_contact_list',
sideContainerId: "contacts_container"
},
'profile': {
id: 'toolbar_button_profile',
sideContainerId: "profile_container"
},
'etherpad': {
id: '#toolbar_button_etherpad'
id: 'toolbar_button_etherpad'
},
'fullscreen': {
id: '#toolbar_button_fullScreen'
id: 'toolbar_button_fullScreen',
className: "button icon-full-screen",
shortcut: 'F',
shortcutAttr: 'toggleFullscreenPopover',
shortcutFunc: function() {
JitsiMeetJS.analytics.sendEvent('shortcut.fullscreen.toggled');
APP.UI.toggleFullScreen();
},
shortcutDescription: "keyboardShortcuts.toggleChat",
content: "Enter / Exit Full Screen",
i18n: "[content]toolbar.fullscreen"
},
'settings': {
id: '#toolbar_button_settings',
id: 'toolbar_button_settings',
sideContainerId: "settings_container"
},
'hangup': {
id: '#toolbar_button_hangup'
id: 'toolbar_button_hangup',
className: "button icon-hangup",
content: "Hang Up",
i18n: "[content]toolbar.hangup"
},
'filmstrip': {
id: '#toolbar_film_strip',
id: 'toolbar_film_strip',
shortcut: "F",
shortcutAttr: "filmstripPopover",
shortcutFunc: function() {
@ -272,6 +308,8 @@ const Toolbar = {
this.toolbarSelector = $("#mainToolbarContainer");
this.extendedToolbarSelector = $("#extendedToolbar");
this._initMainToolbarButtons();
UIUtil.hideDisabledButtons(defaultToolbarButtons);
Object.keys(defaultToolbarButtons).forEach(
@ -298,7 +336,7 @@ const Toolbar = {
APP.UI.addListener(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
function(containerId, isVisible) {
Toolbar._handleSideToolbarContainerToggled( containerId,
Toolbar._handleSideToolbarContainerToggled( containerId,
isVisible);
});
},
@ -617,9 +655,58 @@ const Toolbar = {
if (button.sideContainerId
&& button.sideContainerId === containerId) {
UIUtil.buttonClick(button.id, "selected");
return;
}
}
);
},
/**
* TODO: Fix mic popups
* <a class="button icon-microphone" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
* <ul id="micMutedPopup" class="loginmenu">
* <li data-i18n="[html]toolbar.micMutedPopup"></li>
* </ul>
* <ul id="unableToUnmutePopup" class="loginmenu">
* <li data-i18n="[html]toolbar.unableToUnmutePopup"></li>
* </ul>
* </a>
*/
_initMainToolbarButtons() {
interfaceConfig.MAIN_TOOLBAR_BUTTONS.forEach((value, index) => {
if (value && value in defaultToolbarButtons) {
let button = defaultToolbarButtons[value];
this._addMainToolbarButton(
button,
(index === 0),
(index === interfaceConfig.MAIN_TOOLBAR_BUTTONS.length -1));
}
});
},
_addMainToolbarButton(button, isFirst, isLast) {
let buttonElement = document.createElement("a");
if (button.className)
buttonElement.className = button.className
+ ((isFirst) ? " first" : "")
+ ((isLast) ? " last" : "");
buttonElement.id = button.id;
if (button.shortcutAttr)
buttonElement.setAttribute("shortcut", button.shortcutAttr);
if (button.content)
buttonElement.setAttribute("content", button.content);
if (button.i18n)
buttonElement.setAttribute("data-i18n", button.i18n);
buttonElement.setAttribute("data-container", "body");
buttonElement.setAttribute("data-toggle", "popover");
buttonElement.setAttribute("data-placement", "bottom");
document.getElementById("mainToolbar")
.appendChild(buttonElement);
}
};

View File

@ -18,7 +18,8 @@
* Changes the style class of the element given by id.
*/
buttonClick: function(id, classname) {
$(id).toggleClass(classname); // add the class to the clicked element
// add the class to the clicked element
$("#" + id).toggleClass(classname);
},
/**
* Returns the text width for the given element.

View File

@ -37,6 +37,10 @@ export default {
TOGGLE_CHAT: "UI.toggle_chat",
TOGGLE_SETTINGS: "UI.toggle_settings",
TOGGLE_CONTACT_LIST: "UI.toggle_contact_list",
/**
* Notifies that the profile toolbar button has been clicked.
*/
TOGGLE_PROFILE: "UI.toggle_profile",
/**
* Notifies that a command to toggle the film strip has been issued. The
* event may optionally specify a {Boolean} (primitive) value to assign to