Merge branch 'BeatC-jit/dialogs-redesign'
This commit is contained in:
commit
1238ffbc40
|
@ -1,8 +1,8 @@
|
|||
/* global $, APP, JitsiMeetJS, config, interfaceConfig */
|
||||
import {openConnection} from './connection';
|
||||
//FIXME:
|
||||
import createRoomLocker from './modules/UI/authentication/RoomLocker';
|
||||
//FIXME:
|
||||
import Invite from './modules/UI/invite/Invite';
|
||||
import ContactList from './modules/UI/side_pannels/contactlist/ContactList';
|
||||
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
|
||||
import ConnectionQuality from './modules/connectionquality/connectionquality';
|
||||
|
@ -26,7 +26,7 @@ const ConferenceErrors = JitsiMeetJS.errors.conference;
|
|||
const TrackEvents = JitsiMeetJS.events.track;
|
||||
const TrackErrors = JitsiMeetJS.errors.track;
|
||||
|
||||
let room, connection, localAudio, localVideo, roomLocker;
|
||||
let room, connection, localAudio, localVideo;
|
||||
|
||||
/**
|
||||
* Indicates whether the connection is interrupted or not.
|
||||
|
@ -363,18 +363,7 @@ class ConferenceConnector {
|
|||
switch (err) {
|
||||
// room is locked by the password
|
||||
case ConferenceErrors.PASSWORD_REQUIRED:
|
||||
APP.UI.markRoomLocked(true);
|
||||
roomLocker.requirePassword().then(function () {
|
||||
let pass = roomLocker.password;
|
||||
// we received that password is required, but user is trying
|
||||
// anyway to login without a password, mark room as not locked
|
||||
// in case he succeeds (maybe someone removed the password
|
||||
// meanwhile), if it is still locked another password required
|
||||
// will be received and the room again will be marked as locked
|
||||
if (!pass)
|
||||
APP.UI.markRoomLocked(false);
|
||||
room.join(roomLocker.password);
|
||||
});
|
||||
APP.UI.emitEvent(UIEvents.PASSWORD_REQUIRED);
|
||||
break;
|
||||
|
||||
case ConferenceErrors.CONNECTION_ERROR:
|
||||
|
@ -403,8 +392,7 @@ class ConferenceConnector {
|
|||
}, 5000);
|
||||
|
||||
// notify user that auth is required
|
||||
|
||||
AuthHandler.requireAuth(room, roomLocker.password);
|
||||
AuthHandler.requireAuth(room, this.invite.getRoomLocker().password);
|
||||
break;
|
||||
|
||||
case ConferenceErrors.RESERVATION_ERROR:
|
||||
|
@ -576,6 +564,8 @@ export default {
|
|||
this.isDesktopSharingEnabled =
|
||||
JitsiMeetJS.isDesktopSharingEnabled();
|
||||
|
||||
APP.UI.ContactList = new ContactList(room);
|
||||
|
||||
// if user didn't give access to mic or camera or doesn't have
|
||||
// them at all, we disable corresponding toolbar buttons
|
||||
if (!tracks.find((t) => t.isAudioTrack())) {
|
||||
|
@ -888,7 +878,7 @@ export default {
|
|||
room = connection.initJitsiConference(APP.conference.roomName,
|
||||
this._getConferenceOptions());
|
||||
this._setLocalAudioVideoStreams(localTracks);
|
||||
roomLocker = createRoomLocker(room);
|
||||
this.invite = new Invite(room);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
let email = APP.settings.getEmail();
|
||||
|
@ -1316,13 +1306,6 @@ export default {
|
|||
APP.UI.updateRecordingState(status);
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.LOCK_STATE_CHANGED, (state, error) => {
|
||||
console.log("Received channel password lock change: ", state,
|
||||
error);
|
||||
APP.UI.markRoomLocked(state);
|
||||
roomLocker.lockedElsewhere = state;
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.USER_STATUS_CHANGED, function (id, status) {
|
||||
APP.UI.updateUserStatus(id, status);
|
||||
});
|
||||
|
@ -1348,19 +1331,6 @@ export default {
|
|||
"resizable,scrollbars=yes,status=1");
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.ROOM_LOCK_CLICKED, () => {
|
||||
if (room.isModerator()) {
|
||||
let promise = roomLocker.isLocked
|
||||
? roomLocker.askToUnlock()
|
||||
: roomLocker.askToLock();
|
||||
promise.then(() => {
|
||||
APP.UI.markRoomLocked(roomLocker.isLocked);
|
||||
});
|
||||
} else {
|
||||
roomLocker.notifyModeratorRequired();
|
||||
}
|
||||
});
|
||||
|
||||
APP.UI.addListener(UIEvents.AUDIO_MUTED, muteLocalAudio);
|
||||
APP.UI.addListener(UIEvents.VIDEO_MUTED, muteLocalVideo);
|
||||
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Project animations
|
||||
**/
|
||||
|
||||
/**
|
||||
* START of slide in animation for extended toolbar.
|
||||
*/
|
||||
@include keyframes(slideInX) {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-100%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideInExtX) {
|
||||
0% { transform: translateX(-500%); }
|
||||
100% { transform: translateX(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExtX) {
|
||||
0% { transform: translateX(0%); }
|
||||
100% { transform: translateX(-500%); }
|
||||
}
|
||||
|
||||
/**
|
||||
* END of slide out animation for extended toolbar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START of slide in / out animation for main toolbar.
|
||||
*/
|
||||
@include keyframes(slideInY) {
|
||||
100% { transform: translateY(0%); }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutY) {
|
||||
0% { transform: translateY(0%); }
|
||||
100% { transform: translateY(-100%); }
|
||||
}
|
||||
|
||||
/**
|
||||
* END of slide in / out animation for main toolbar.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START of slide in animation for extended toolbar (inner) panel.
|
||||
*/
|
||||
|
||||
// FIX: Can't use percentage because of breaking animation when width is changed
|
||||
// (100% of 0 is also zero) Extracted this to config variable.
|
||||
@include keyframes(slideInExt) {
|
||||
from { left: -$sidebarWidth; }
|
||||
to { left: 0; }
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExt) {
|
||||
from { left: 0; }
|
||||
to { left: -$sidebarWidth; }
|
||||
}
|
||||
|
||||
/**
|
||||
* END of slide in animation for extended toolbar (inner) panel.
|
||||
*/
|
||||
|
||||
/**
|
||||
* START of slide in animation for extended toolbar container
|
||||
**/
|
||||
|
||||
@include keyframes(slideOutExtContainer) {
|
||||
from { width: $sidebarWidth; }
|
||||
to { width: 0; }
|
||||
}
|
||||
|
||||
@include keyframes(slideInExtContainer) {
|
||||
from { width: 0; }
|
||||
to { width: $sidebarWidth; }
|
||||
}
|
||||
|
||||
/**
|
||||
* END of slide in animation for extended toolbar container
|
||||
**/
|
|
@ -13,6 +13,10 @@ html, body{
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html, body, input, textarea, keygen, select, button {
|
||||
font-family: $baseFontFamily !important;
|
||||
}
|
||||
|
@ -26,16 +30,17 @@ html, body, input, textarea, keygen, select, button {
|
|||
}
|
||||
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
color: $defaultDarkColor;
|
||||
width: 100%;
|
||||
padding: 5px 7px;
|
||||
color: $inputColor;
|
||||
border-radius: $borderRadius;
|
||||
line-height: 32px;
|
||||
letter-spacing: $letterSpacing;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
border:1px solid $inputBorderColor;
|
||||
background-color: $inputBackground;
|
||||
outline: none; /* removes the default outline */
|
||||
resize: none; /* prevents the user-resizing, adjust to taste */
|
||||
}
|
||||
|
@ -43,7 +48,8 @@ input[type='text'], input[type='password'], textarea {
|
|||
textarea {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
resize: horizontal;
|
||||
resize: none;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
button.no-icon {
|
||||
|
@ -53,12 +59,9 @@ button.no-icon {
|
|||
button, input, select, textarea {
|
||||
margin: 0;
|
||||
vertical-align: baseline;
|
||||
color: $defaultDarkColor;
|
||||
background: $inputLightBackground;
|
||||
font-size: 12px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
color: $inputColor;
|
||||
font-size: 1em;
|
||||
letter-spacing: $letterSpacing;
|
||||
}
|
||||
|
||||
button, select, input[type="button"],
|
||||
|
@ -72,7 +75,7 @@ input[type="reset"], input[type="submit"] {
|
|||
|
||||
button {
|
||||
color: #FFF;
|
||||
background-color: $buttonBackground !important;
|
||||
background-color: $buttonBackground;
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
|
||||
|
@ -159,6 +162,9 @@ form {
|
|||
display: flex !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tooltips
|
||||
**/
|
||||
.tipsy {
|
||||
z-index: $tooltipsZ;
|
||||
&-inner {
|
||||
|
@ -169,3 +175,26 @@ form {
|
|||
border-color: $tooltipBg;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialogs fade
|
||||
*/
|
||||
.aui-blanket {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: $linkFontColor;
|
||||
@include transition(color .1s ease-out);
|
||||
|
||||
&:hover {
|
||||
color: $linkHoverFontColor;
|
||||
text-decoration: underline;
|
||||
@include transition(color .1s ease-in);
|
||||
}
|
||||
}
|
||||
|
||||
#inviteLinkRef {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
> ul#contacts {
|
||||
font-size: 12px;
|
||||
bottom: 0px;
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
margin-top: 16px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
@ -24,7 +25,7 @@
|
|||
white-space: nowrap;
|
||||
color: #FFF;
|
||||
font-size: 10pt;
|
||||
padding: 6px 10%;
|
||||
padding: 6px 30px;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/* Functions */
|
||||
|
||||
/* Pixels to Ems function */
|
||||
@function em($value, $base: 16) {
|
||||
@return #{$value / $base}em;
|
||||
}
|
|
@ -18,6 +18,14 @@
|
|||
animation: $animations;
|
||||
}
|
||||
|
||||
@mixin flex() {
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyframes mixin.
|
||||
*/
|
||||
|
@ -63,3 +71,9 @@
|
|||
-webkit-transition: $transition;
|
||||
transition: $transition;
|
||||
}
|
||||
|
||||
@mixin box-shadow($type, $h, $y, $blur, $color) {
|
||||
-webkit-box-shadow: $type $h $y $blur $color;
|
||||
-moz-box-shadow: $type $h $y $blur $color;
|
||||
box-shadow: $type $h $y $blur $color;
|
||||
}
|
|
@ -19,11 +19,6 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.jqibuttons button {
|
||||
margin-right: 5px;
|
||||
float:right;
|
||||
}
|
||||
|
||||
button.jqidefaultbutton #inviteLinkRef {
|
||||
color: #2c8ad2;
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
position:absolute;
|
||||
top: 0px;
|
||||
left: $defaultToolbarSize;
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
max-width: 200px;
|
||||
width: 0;
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
height: 100%;
|
||||
max-width: $sidebarWidth;
|
||||
z-index: 800;
|
||||
overflow: hidden;
|
||||
letter-spacing: 1px;
|
||||
letter-spacing: $titleLetterSpacing;
|
||||
|
||||
/**
|
||||
* Labels inside the side panel.
|
||||
|
@ -24,7 +24,8 @@
|
|||
/**
|
||||
* Form elements and blocks.
|
||||
*/
|
||||
input, label, select, button, a, .sideToolbarBlock {
|
||||
input, label, select, a,
|
||||
.sideToolbarBlock, .input-control, .button-control {
|
||||
display: inline-block;
|
||||
margin-top: 15px;
|
||||
margin-left: 10%;
|
||||
|
@ -36,7 +37,7 @@
|
|||
*/
|
||||
select, input[type="button"], input[type="text"],
|
||||
input[type="reset"], input[type="submit"] {
|
||||
color: $defaultColor;
|
||||
color: $inputColor;
|
||||
background: $inputBackground;
|
||||
border: none;
|
||||
}
|
||||
|
@ -63,7 +64,10 @@
|
|||
*/
|
||||
.sideToolbarContainer__inner {
|
||||
display: none;
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
width: $sidebarWidth;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
color: #FFF;
|
||||
|
||||
/**
|
||||
|
@ -100,6 +104,14 @@
|
|||
.first {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buttons in the side toolbar container.
|
||||
*/
|
||||
.button-control {
|
||||
margin: 9px 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,13 +45,13 @@
|
|||
border-radius: 3px;
|
||||
|
||||
.first {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
}
|
||||
|
||||
.last {
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* Theme
|
||||
*/
|
||||
@import 'themes/light';
|
||||
|
||||
/**
|
||||
* Style variables
|
||||
*/
|
||||
|
@ -21,7 +26,8 @@ $thumbnailToolbarHeight: 25px;
|
|||
*/
|
||||
$defaultColor: #F1F1F1;
|
||||
$defaultSideBarFontColor: #44A5FF;
|
||||
$defaultDarkColor: #4F4F4F;
|
||||
$defaultSemiDarkColor: #ACACAC;
|
||||
$defaultDarkColor: #2b3d5c;
|
||||
$defaultBackground: #474747;
|
||||
$tooltipBg: rgba(0,0,0, 0.7);
|
||||
|
||||
|
@ -33,11 +39,8 @@ $toolbarBadgeColor: #FFFFFF;
|
|||
$toolbarToggleBackground: #12499C;
|
||||
|
||||
// Main controls
|
||||
$inputBackground: rgba(132, 132, 132, .5);
|
||||
$inputSemiBackground: rgba(132, 132, 132, .8);
|
||||
$inputLightBackground: #EBEBEB;
|
||||
$inputBorderColor: #EBEBEB;
|
||||
$buttonBackground: #44A5FF;
|
||||
|
||||
// Video layout.
|
||||
$videoThumbnailHovered: #BFEBFF;
|
||||
|
@ -58,10 +61,25 @@ $rateStarLabelColor: #333;
|
|||
*/
|
||||
$borderRadius: 4px;
|
||||
$defaultWatermarkLink: '../images/watermark.png';
|
||||
$sidebarWidth: 200px;
|
||||
|
||||
/**
|
||||
* Z-indexes. TODO: Replace this by a function.
|
||||
*/
|
||||
$tooltipsZ: 901;
|
||||
$toolbarZ: 900;
|
||||
$overlayZ: 800;
|
||||
$overlayZ: 800;
|
||||
|
||||
/**
|
||||
* Font Colors TODO: Change colors when general dialogs are implemented.
|
||||
*/
|
||||
$defaultFontColor: #777;
|
||||
$defaultLightFontColor: #F1F1F1;
|
||||
$defaultDarkFontColor: #000;
|
||||
$buttonFontColor: #777;
|
||||
$buttonHoverFontColor: #287ade;
|
||||
$auiPrimaryButtonBg: #3572b0;
|
||||
$auiPrimaryButtonHoverBg: #57647b;
|
||||
$auiPrimaryButtonColor: #fff;
|
||||
$auiIconColor: #707070;
|
||||
$inputControlEmColor: #f29424;
|
|
@ -0,0 +1,81 @@
|
|||
.button-control {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
border: 1px solid $buttonBorder;
|
||||
vertical-align: baseline;
|
||||
height: 30px;
|
||||
padding: 4px 10px;
|
||||
margin: 0;
|
||||
line-height: 1.5em;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
float: right;
|
||||
font-size: 14px;
|
||||
margin-left: 10px;
|
||||
color: $buttonColor;
|
||||
letter-spacing: $letterSpacing;
|
||||
font-weight: $buttonFontWeight;
|
||||
@include transition(background-color .1s ease-out);
|
||||
|
||||
&[disabled] {
|
||||
color: #666;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&_full-width {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $buttonHoverBorder;
|
||||
background-color: $buttonHoverBackground;
|
||||
@include transition(background-color .1s ease-in);
|
||||
}
|
||||
|
||||
&:active {
|
||||
@include box-shadow(inset, 0, 0, 1px, $buttonShadowColor);
|
||||
}
|
||||
|
||||
&_light {
|
||||
color: $defaultDarkColor;
|
||||
background-color: $buttonLightBackground;
|
||||
border: 1px solid $buttonLightBorder;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $buttonLightHoverBorder;
|
||||
background-color: $buttonLightHoverBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&_link {
|
||||
color: $buttonLinkColor;
|
||||
background-color: $buttonLinkBackground;
|
||||
|
||||
&:hover {
|
||||
background-color: $buttonLinkBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&_primary {
|
||||
background-color: $primaryButtonBackground;
|
||||
border: 1px solid $primaryButtonBackground;
|
||||
color: $primaryButtonColor;
|
||||
font-weight: $primaryButtonFontWeight;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $primaryButtonHoverBackground;
|
||||
background-color: $primaryButtonHoverBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&_close {
|
||||
color: $defaultFontColor;
|
||||
}
|
||||
&_submit {
|
||||
color: $linkFontColor;
|
||||
&:hover {
|
||||
color: $linkHoverFontColor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
.input-control {
|
||||
padding: 16px 0;
|
||||
|
||||
&__text {
|
||||
margin: 8px 0;
|
||||
font-size: 1em
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 1em;
|
||||
font-weight: $labelFontWeight;
|
||||
}
|
||||
|
||||
&__input {
|
||||
margin: 8px 0;
|
||||
|
||||
&::selection {
|
||||
background-color: $defaultDarkSelectionColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__em {
|
||||
color: $inputControlEmColor;
|
||||
}
|
||||
|
||||
&__hint {
|
||||
margin-top: 0;
|
||||
font-size: $hintFontSize;
|
||||
|
||||
span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&__container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
@include flex();
|
||||
|
||||
.button-control {
|
||||
margin: 9px 0 9px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
/* Functions BEGIN */
|
||||
|
||||
@import 'functions';
|
||||
|
||||
/* Functions END */
|
||||
|
||||
/* Variables BEGIN */
|
||||
|
||||
@import 'variables';
|
||||
|
@ -10,6 +16,12 @@
|
|||
|
||||
/* Mixins END */
|
||||
|
||||
/* Animations BEGIN */
|
||||
|
||||
@import "animations";
|
||||
|
||||
/* Animations END */
|
||||
|
||||
/* Fonts BEGIN */
|
||||
|
||||
@import 'font';
|
||||
|
@ -17,6 +29,10 @@
|
|||
|
||||
/* Fonts END */
|
||||
|
||||
/* Theme BEGIN */
|
||||
@import "themes/light";
|
||||
/* Theme END */
|
||||
|
||||
/* Modules BEGIN */
|
||||
|
||||
@import 'toastr';
|
||||
|
@ -25,8 +41,6 @@
|
|||
@import 'modals/dialog';
|
||||
@import 'modals/feedback/feedback';
|
||||
@import 'videolayout_default';
|
||||
@import 'jquery-impromptu';
|
||||
@import 'modaldialog';
|
||||
@import 'notice';
|
||||
@import 'popup_menu';
|
||||
@import 'recording';
|
||||
|
@ -43,6 +57,8 @@
|
|||
@import 'jquery.contextMenu';
|
||||
@import 'keyboard-shortcuts';
|
||||
@import 'redirect_page';
|
||||
|
||||
@import 'input-control/input-control';
|
||||
@import 'shortcuts/main';
|
||||
@import 'buttons/button-control';
|
||||
|
||||
/* Modules END */
|
|
@ -1,53 +1,80 @@
|
|||
.dialog{
|
||||
.dialog {
|
||||
visibility: visible;
|
||||
height: auto;
|
||||
|
||||
p {
|
||||
color: $defaultDarkColor;
|
||||
h3 {
|
||||
color: $auiDialogColor;
|
||||
}
|
||||
textarea {
|
||||
background: none;
|
||||
border: 1px solid $inputBorderColor;
|
||||
}
|
||||
.aui-dialog2-content:last-child {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
.aui-dialog2-content:first-child {
|
||||
border-top-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
.aui-dialog2-footer{
|
||||
border-top: 0;
|
||||
border-radius: 0;
|
||||
padding-top: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
height: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.aui-button {
|
||||
height: 28px;
|
||||
font-size: 12px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
|
||||
&_close {
|
||||
font-weight: 400 !important;
|
||||
color: $buttonBackground;
|
||||
background: none !important;
|
||||
.aui {
|
||||
|
||||
:hover {
|
||||
text-decoration: underline;
|
||||
&-icon {
|
||||
color: $auiDialogColor;
|
||||
|
||||
&-small {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
&_submit {
|
||||
font-weight: 700 !important;
|
||||
color: $defaultColor;
|
||||
background: $buttonBackground;
|
||||
border-radius: 3px;
|
||||
|
||||
&-iconfont-close-dialog {
|
||||
cursor: pointer;
|
||||
right: 20px;
|
||||
position: absolute;
|
||||
top: -49px;
|
||||
}
|
||||
|
||||
&-dialog2 {
|
||||
&-header, &-footer {
|
||||
background-color: $auiDialogBg;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&-header {
|
||||
height: em(58, 12);
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
|
||||
h2 {
|
||||
font-size: em(20, 12);
|
||||
font-weight: $dialogTitleFontWeight;
|
||||
letter-spacing: $titleLetterSpacing;
|
||||
color: $auiDialogColor;
|
||||
}
|
||||
|
||||
&-main {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
border-top: 1px solid $auiBorderColor;
|
||||
}
|
||||
|
||||
&-content {
|
||||
font-size: em(14, 12);
|
||||
min-height: 0;
|
||||
background-color: $auiDialogContentBg;
|
||||
color: $auiDialogColor;
|
||||
|
||||
p,span, h3 {
|
||||
font-weight: $labelFontWeight;
|
||||
letter-spacing: $letterSpacing;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-control:not(:last-child) {
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,64 +45,60 @@
|
|||
animation-timing-function: ease-in-out
|
||||
}
|
||||
|
||||
.feedback {
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
font-size: 24px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
p {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
text-align: center;
|
||||
|
||||
textarea {
|
||||
text-align: left;
|
||||
min-height: 80px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&__footer {
|
||||
|
||||
&:hover {
|
||||
color: #287ade;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
&__rating {
|
||||
line-height: 1.2;
|
||||
padding: 20px 0;
|
||||
|
||||
p {
|
||||
margin: 10px 0 0;
|
||||
.feedback.aui-dialog2{
|
||||
.aui-dialog2{
|
||||
&-header {
|
||||
background-color: $auiDialogContentBg;
|
||||
border-bottom-color: transparent;
|
||||
padding-top: 30px;
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.star-label {
|
||||
font-size: 16px;
|
||||
color: $rateStarLabelColor;
|
||||
}
|
||||
&-content {
|
||||
text-align: center;
|
||||
padding: 10px 40px 20px 40px;
|
||||
|
||||
.star-btn {
|
||||
color: $rateStarDefault;
|
||||
font-size: 36px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
@include transition(all .2s ease);
|
||||
.rating {
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
|
||||
&.starHover,
|
||||
&.active,
|
||||
&:hover {
|
||||
color: $rateStarActivity;
|
||||
> i:before {
|
||||
content: "\e90a";
|
||||
.star-label {
|
||||
height: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
};
|
||||
.star-btn {
|
||||
color: $rateStarDefault;
|
||||
font-size: 36px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
@include transition(all .2s ease);
|
||||
|
||||
&.starHover,
|
||||
&.active,
|
||||
&:hover {
|
||||
color: $rateStarActivity;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
padding-left: 60px;
|
||||
padding-right: 60px;
|
||||
margin-top: 20px;
|
||||
textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-footer {
|
||||
background-color: $auiDialogContentBg;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/* Import shortcuts blocks */
|
||||
|
||||
@import 'regular-key';
|
||||
@import 'shortcuts-list';
|
|
@ -0,0 +1,11 @@
|
|||
.regular-key {
|
||||
display: table-cell;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-family: $baseFontFamily;
|
||||
color: $defaultDarkColor;
|
||||
font-size: 12px;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
.shortcuts-list {
|
||||
padding: 0;
|
||||
|
||||
&__description {
|
||||
margin-left: em(16, 14);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
&__item {
|
||||
margin-bottom: em(7, 14);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Buttons
|
||||
*/
|
||||
$buttonBackground: #f5f5f5;
|
||||
$buttonHoverBackground: #e9e9e9;
|
||||
$buttonBorder: #ccc;
|
||||
$buttonHoverBorder: #999;
|
||||
$buttonColor: #333;
|
||||
|
||||
$buttonLightBackground: #f5f5f5;
|
||||
$buttonLightHoverBackground: #e9e9e9;
|
||||
$buttonLightBorder: #ccc;
|
||||
$buttonLightHoverBorder: #999;
|
||||
|
||||
$buttonLinkBackground: transparent;
|
||||
$buttonLinkColor: #0090e8;
|
||||
|
||||
$primaryButtonBackground: #3572b0;
|
||||
$primaryButtonHoverBackground: #2a67a5;
|
||||
$primaryButtonColor: #fff;
|
||||
$primaryButtonFontWeight: 400;
|
||||
|
||||
$buttonShadowColor: #192d4f;
|
||||
|
||||
/**
|
||||
* Dialog colors
|
||||
**/
|
||||
$auiDialogColor: #333;
|
||||
$auiDialogBg: #f5f5f5;
|
||||
$auiDialogContentBg: #fff;
|
||||
$auiBorderColor: #ccc;
|
||||
$dialogTitleFontWeight: 400;
|
||||
|
||||
// Main controls
|
||||
$inputBackground: #fff;
|
||||
$inputBorderColor: #ccc;
|
||||
$inputColor: #333;
|
||||
$defaultDarkSelectionColor: #ccc;
|
||||
$titleLetterSpacing: 0;
|
||||
$letterSpacing: 0;
|
||||
$buttonFontWeight: 400;
|
||||
$labelFontWeight: 400;
|
||||
$hintFontSize: em(13, 14);
|
||||
$linkFontColor: #3572b0;
|
||||
$linkHoverFontColor: darken(#3572b0, 10%);
|
||||
$dropdownColor: #333;
|
|
@ -132,7 +132,6 @@
|
|||
</span>
|
||||
</a>
|
||||
<a class="button" id="toolbar_button_record" style="display: none"></a>
|
||||
<a class="button icon-security" id="toolbar_button_security"></a>
|
||||
<a class="button icon-share-doc" id="toolbar_button_etherpad"></a>
|
||||
<a class="button icon-shared-video" id="toolbar_button_sharedvideo" style="display: none">
|
||||
<ul id="sharedVideoMutedPopup" class="loginmenu extendedToolbarPopup">
|
||||
|
@ -254,12 +253,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
||||
<div class="header"><h3 data-i18n="keyboardShortcuts.keyboardShortcuts"></h3></div>
|
||||
<div class="content">
|
||||
<ul id="keyboard-shortcuts-list" class="item">
|
||||
<ul id="keyboard-shortcuts-list" class="shortcuts-list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="aui-feedback-dialog" class="dialog feedback aui-layer aui-dialog2 aui-dialog2-medium" style="display: none;"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -42,6 +42,7 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
|||
// Enables feedback star animation.
|
||||
ENABLE_FEEDBACK_ANIMATION: false,
|
||||
DISABLE_FOCUS_INDICATOR: false,
|
||||
DISABLE_DOMINANT_SPEAKER_INDICATOR: false,
|
||||
AUDIO_LEVEL_PRIMARY_COLOR: "rgba(255,255,255,0.7)",
|
||||
AUDIO_LEVEL_SECONDARY_COLOR: "rgba(255,255,255,0.4)"
|
||||
};
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
"en": "Անգլերեն",
|
||||
"bg": "Բուլղարերեն",
|
||||
"de": "Գերմաներեն ",
|
||||
"es": "",
|
||||
"es": "Իսպաներեն",
|
||||
"fr": "Ֆրանսերեն",
|
||||
"hy": "",
|
||||
"hy": "Հայերեն",
|
||||
"it": "Իտալերեն",
|
||||
"oc": "",
|
||||
"ptBR": "",
|
||||
"oc": "Օքսիտաներեն",
|
||||
"pl": "Լեհերեն",
|
||||
"ptBR": "Պորտուգալերեն (Բրազիլիա)",
|
||||
"ru": "Ռուսերեն",
|
||||
"sk": "Սլովակերեն",
|
||||
"sl": "Սլովեներեն ",
|
||||
"sv": "Շվեդերեն ",
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
"en": "Anglés",
|
||||
"bg": "Bulgar",
|
||||
"de": "Aleman",
|
||||
"es": "",
|
||||
"es": "Castelhan",
|
||||
"fr": "Francés",
|
||||
"hy": "",
|
||||
"hy": "Armenian",
|
||||
"it": "Italian",
|
||||
"oc": "",
|
||||
"ptBR": "",
|
||||
"oc": "Occitan",
|
||||
"pl": "Polonés",
|
||||
"ptBR": "Portugués (Brasil)",
|
||||
"ru": "Rus",
|
||||
"sk": "Eslovac",
|
||||
"sl": "Eslovèn",
|
||||
"sv": "Suedés",
|
||||
|
|
|
@ -1,39 +1,37 @@
|
|||
{
|
||||
"contactlist": "ԿՈՆՏԱԿՏՆԵՐ",
|
||||
"contactlist": "Զանգ",
|
||||
"connectionsettings": "Միացման կարգավորումներ",
|
||||
"poweredby": "Հիմնված է",
|
||||
"downloadlogs": "Բեռնել log-էրը",
|
||||
"feedback": "Հայտնեք ձեր կարծիքը",
|
||||
"roomUrlDefaultMsg": "Ձեր կոնֆերանսը այժմ ստեղծվում է...",
|
||||
"participant": "Մասնակից",
|
||||
"me": "ես",
|
||||
"speaker": "Հռետոր",
|
||||
"raisedHand": "",
|
||||
"raisedHand": "Ցանկանում է խոսել",
|
||||
"defaultNickname": "օրինակ՝ Պողոս Պողոսյան",
|
||||
"defaultLink": "օրինակ՝ __url__",
|
||||
"calling": "",
|
||||
"callingName": "__անուն__",
|
||||
"userMedia": {
|
||||
"react-nativeGrantPermissions": "",
|
||||
"chromeGrantPermissions": "",
|
||||
"androidGrantPermissions": "",
|
||||
"firefoxGrantPermissions": "",
|
||||
"operaGrantPermissions": "",
|
||||
"firefoxGrantPermissions": "Խնդրում ենք տրամադրել տեսախցիկը և խոսափողը օգտագործելու թույլտվություններ <b> <i> տարածել նշված սարքը </ i> </ b> կոճակը",
|
||||
"operaGrantPermissions": "Խնդրում ենք տրամադրել տեսախցիկը և խոսափողը օգտագործելու թույլտվություններ <b> <i>ընդունել</ i> </ b> կոճակը",
|
||||
"iexplorerGrantPermissions": "",
|
||||
"safariGrantPermissions": "",
|
||||
"nwjsGrantPermissions": ""
|
||||
"safariGrantPermissions": "Խնդրում ենք տրամադրել տեսախցիկը և խոսափողը օգտագործելու թույլտվություններ <b> <i>Այո</ i> </ b> կոճակը",
|
||||
"nwjsGrantPermissions": "Խնդրում ենք տրամադրել տեսախցիկը և խոսափողը օգտագործելու թույլտվություններ"
|
||||
},
|
||||
"keyboardShortcuts": {
|
||||
"keyboardShortcuts": "",
|
||||
"raiseHand": "",
|
||||
"pushToTalk": "",
|
||||
"toggleScreensharing": "",
|
||||
"toggleFilmstrip": "",
|
||||
"toggleShortcuts": "",
|
||||
"focusLocal": "",
|
||||
"focusRemote": "",
|
||||
"toggleChat": "",
|
||||
"mute": "",
|
||||
"videoMute": ""
|
||||
"keyboardShortcuts": "Ստեղնաշարի դյուրանցումներ (shortcuts)",
|
||||
"raiseHand": "Բարձրացրեք Ձեր ձեռքը",
|
||||
"pushToTalk": "Սեղմեք խոսելու համար",
|
||||
"toggleScreensharing": "Անցնել ֆոտոխցիկի և էկրանի փոխանակման միջև",
|
||||
"toggleFilmstrip": "Ցույց տալ կամ թաքցնել տեսանյութերը",
|
||||
"toggleShortcuts": "Ցույց տալ կամ թաքցնել այս օգնության մենյուն",
|
||||
"focusLocal": "Կենտրոնանալ տեղական տեսանյութի վրա",
|
||||
"focusRemote": "Կենտրոնանալ տեղական տեսանյութի վրա",
|
||||
"toggleChat": "Բացել կամ փակել չատի պանելը",
|
||||
"mute": "Անջատել կամ միացնել խոսափողը",
|
||||
"videoMute": "Կանգնեցնել կամ սկսել տեղական տեսանյութը"
|
||||
},
|
||||
"welcomepage": {
|
||||
"go": "ՄՈՒՏՔ",
|
||||
|
@ -45,7 +43,7 @@
|
|||
},
|
||||
"feature2": {
|
||||
"title": "Պետք չէ արագ կապ",
|
||||
"content": "Բազմամասնակից վիդեո կոնֆերանսները աշխատում են ընդամենը 128 Կբ/վ արագությամբ: Իսկ միայն էկրանի ցուցադրման կամ միայն ձայնի դեպքում՝ ավելի քիչ:"
|
||||
"content": "Բազմամասնակից վիդեո կոնֆերանսները աշխատում են ընդամենը 128 Կբ/վ թողունակությամբ: Իսկ միայն ձայնի կամ էկրանի ցուցադրման դեպքում՝ ավելի քիչ:"
|
||||
},
|
||||
"feature3": {
|
||||
"title": "Բաց կոդ",
|
||||
|
@ -92,12 +90,14 @@
|
|||
"sharedVideoMutedPopup": "Ձեր ցուցադրված տեսանյութի ձայնը անջատված է, այնպես որ <br />, կարող եք խոսել մյուս մասնակիցների հետ:",
|
||||
"micMutedPopup": "Ձեր խոսափողը անջատված է՝<br/> կարող եք լիովին վայելել ձեր ցուցադրված տեսանյութը:",
|
||||
"unableToUnmutePopup": "Դուք չեք կարող միացնել ձայնը, քանի դեռ միանցված է ցուցադրվող տեսանյութը:",
|
||||
"cameraDisabled": "",
|
||||
"micDisabled": ""
|
||||
"cameraDisabled": "Տեսախցիկը հասանելի չէ",
|
||||
"micDisabled": "Խոսափողը հասանելի չէ",
|
||||
"filmstrip": "",
|
||||
"raiseHand": "Բարձրացրեք ձեռքը խոսելու համար"
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "Բացել/փակել չատը",
|
||||
"filmstrip": "Ցույղ տալ/թաքցնել ժապավենը",
|
||||
"filmstrip": "Ցույց տալ/թաքցնել տեսանյութները",
|
||||
"contactlist": "Բացել/փակել կոնտակտների ցուցակը"
|
||||
},
|
||||
"chat": {
|
||||
|
@ -108,28 +108,37 @@
|
|||
"messagebox": "Գրեք տեքստ..."
|
||||
},
|
||||
"settings": {
|
||||
"title": "ԿԱՐԳԱՎՈՐՈՒՄՆԵՐ",
|
||||
"title": "Կարգավորումներ",
|
||||
"update": "Թարմացնել",
|
||||
"name": "Անուն",
|
||||
"startAudioMuted": "Սկսել առանց ձայնի",
|
||||
"startVideoMuted": "Սկսել առանց վիդեոյի",
|
||||
"selectCamera": "Ընտրեք տեսախցիկը",
|
||||
"selectMic": "Ընտրեք խոսափողը",
|
||||
"selectAudioOutput": "",
|
||||
"followMe": "Թույլ տալ ինձ հետևելը",
|
||||
"noDevice": "",
|
||||
"noPermission": "",
|
||||
"avatarUrl": ""
|
||||
"startAudioMuted": "Բոլորը սկսեն անջատած ձայնով",
|
||||
"startVideoMuted": "Բոլորը սկսեցին թաքնված",
|
||||
"selectCamera": "Տեսախցիկ",
|
||||
"selectMic": "Խոսափող",
|
||||
"selectAudioOutput": "Ձայնային ելք",
|
||||
"followMe": "Բոլորը հետևում են ինձ",
|
||||
"noDevice": "Ոչինչ",
|
||||
"noPermission": "Սարքը օգտագործելու թույլտվությունը տրված չէ",
|
||||
"cameraAndMic": "Տեսախցիկ և խոսափող",
|
||||
"moderator": "MODERATOR",
|
||||
"password": "Դնել գաղտնաբառ",
|
||||
"audioVideo": "ձայն և տեսանյութ",
|
||||
"setPasswordLabel": "Փակել սենյակը գաղտնաբառով"
|
||||
},
|
||||
"profile": {
|
||||
"title": "Էջ",
|
||||
"setDisplayNameLabel": "Դնել Ձեր երևացող անունը",
|
||||
"setEmailLabel": "Սահմանեք Ձեր gravatar էլ.փոստը"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"editnickname": "Սեղմեք Ձեր անունը <br/>փոխելու համար",
|
||||
"moderator": "Այս կոնֆերանսի տերը",
|
||||
"videomute": "Մասնակիցը անջատեց<br/>իր տեսախցիկը",
|
||||
"videomute": "Մասնակիցը անջատեց <br/>իր տեսախցիկը",
|
||||
"mute": "Մասնակիցը անջատեց ձայնը",
|
||||
"kick": "Դուրս հանել",
|
||||
"muted": "Ձայնը անջատված է",
|
||||
"domute": "Անջատել ձայնը",
|
||||
"flip": ""
|
||||
"flip": "Շրջել"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"bitrate": "Բիթրեյթ",
|
||||
|
@ -158,7 +167,7 @@
|
|||
"grantedToUnknown": "Կարգավորիչի իրավունքները տրամադրված է $t(somebody)! -ին",
|
||||
"muted": "Դուք խոսակցությունը սկսեցիք անջատած ձայնով:",
|
||||
"mutedTitle": "Ձեր ձայնը անջատվա'ծ է",
|
||||
"raisedHand": ""
|
||||
"raisedHand": "Ցանկանում է խոսել"
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "Վա՜յ: Ձեզ դուրս հանեցին հանդիպումից:",
|
||||
|
@ -168,6 +177,7 @@
|
|||
"connectError": "Ու՜պս! Ինչոր բան այն չէ և մենք չկարողացանք միանալ կոնֆերանսին:",
|
||||
"connectErrorWithMsg": "Ու՜պս! Ինչոր բան այն չէ և մենք չկարողացանք միանալ կոնֆերանսին: __msg__",
|
||||
"connecting": "Միանում է...",
|
||||
"copy": "Պատճենել",
|
||||
"error": "Սխալ",
|
||||
"detectext": "Սխալ, երբ փորձում է հայտնաբերել էկրանի ցուցադրման ընդլայնումը:",
|
||||
"failtoinstall": "Չհաջողվեց տեղադրել էկրանի ցուցադրման ընդլայնումը",
|
||||
|
@ -179,8 +189,8 @@
|
|||
"lockMessage": "Ձախողվեց արգելափակել կոնֆերանսը:",
|
||||
"warning": "Ուշադրությու՝ն",
|
||||
"passwordNotSupported": "Սենյակների գաղտնաբառերը ներկայումս չեն ապահովվում:",
|
||||
"sorry": "Ներողություն",
|
||||
"internalError": "Ներքին ծրագրային սխալ [setRemoteDescription]",
|
||||
"internalErrorTitle": "ներքին սխալ ",
|
||||
"internalError": "Վայ: Ինչ-որ բան այնպես չէ .Հետեւյալը սխալն է տեղի ունեցել [setRemoteDescription]",
|
||||
"unableToSwitch": "Անհնար է անցնել վիդեո հոսքին:",
|
||||
"SLDFailure": "Ու՜պս: Ինչ-որ բան գնաց սխալ, և մենք չկարողացանք անջատել ձայնը (SLD Failure)",
|
||||
"SRDFailure": "Ու՜պս: Ինչ-որ բան գնաց սխալ, և մենք չկարողացանք անջատել տեսահոսքը (SRD Failure)",
|
||||
|
@ -212,26 +222,28 @@
|
|||
"sipMsg": "Նշեք SIP համարը",
|
||||
"passwordCheck": "Դուք վստա՞հ էք որ ցանկանում էք ջնջել Ձեր գաղտնաբառը։",
|
||||
"passwordMsg": "Սահմանել գաղտնաբառ ձեր սենյակը կողպելու համար",
|
||||
"Invite": "Հրավիրել",
|
||||
"shareLink": "Տարածել այս հղումը բոլոր նրանց ում կհրավիրեմ:",
|
||||
"shareLink": "Պատճենել և կիսվել այս հղումով",
|
||||
"settings1": "Կարգավորել Ձեր կոնֆերանսը",
|
||||
"settings2": "Մասնակիցները միացան անջատվախ ձայնով",
|
||||
"settings3": "Պահանջվում է մականունը<br/><br/>Դրեք գաղտնաբառ Ձեր սենյակը արգելափակելու համար",
|
||||
"yourPassword": "Ձեր գաղտնաբառը",
|
||||
"yourPassword": "Մուտքագրեք նոր գաղտնաբառ:",
|
||||
"Back": "Վերադառնալ",
|
||||
"serviceUnavailable": "Ծառայությունը անհասանելի է",
|
||||
"gracefulShutdown": "Մեր ծառայությունը ներկայումս չի գործում տեխնիկական սպասարկման համար: Խնդրում ենք փորձեք ավելի ուշ:",
|
||||
"Yes": "Այո",
|
||||
"reservationError": "Վերապահման համակարգի սխալ",
|
||||
"reservationErrorMsg": "Սխալ. __code__, ծանուցում. __msg__",
|
||||
"password": "Գաղտնաբառ",
|
||||
"password": "Գրեք գաղտնաբառը",
|
||||
"userPassword": "օգտագործողի գաղտնաբառը",
|
||||
"token": "սիմվոլ",
|
||||
"tokenAuthFailed": "Սխալ: XMPP սերվեր մուտք գործելուց. սխալ սիմվոլ",
|
||||
"tokenAuthFailedTitle": "Վավերացումը չի ստացվել",
|
||||
"tokenAuthFailed": "Ներողություն,Դուք ընդունված չեք այս զանգին միանալու համար",
|
||||
"displayNameRequired": "Խնդրում ենք մուտքագրել Ձեր ցուցադրման անունը",
|
||||
"extensionRequired": "Ընդլայնում է պահանջվում:",
|
||||
"firefoxExtensionPrompt": "Դուք պետք է տեղադրեք Firefox ընդլայնում, որպեսզի օգտագործել էկրանի փոխանակման ռեժիմը: Խնդրում ենք փորձեք կրկին՝ այն <a href='__url__'> այստեղից ձեռք բերելուց հետո</a>:",
|
||||
"feedbackQuestion": "Ինչպիսին էր ձեր զանգը:",
|
||||
"rateExperience": "Խնդրում ենք ներկայացրեք Ձեր հանդիպման փորձը",
|
||||
"feedbackHelp": "Ձեր կարծիքը կօգնի մեզ բարելավել ձեր տեսափորձը",
|
||||
"feedbackQuestion": "Պատմեք մեզ Ձեր զանգի մասին",
|
||||
"thankYou": "Շնորհակալություն __appName__ -ից օգտվելու համար:",
|
||||
"sorryFeedback": "Մենք շատ ցավում ենք լսել դա: Կուզե՞ք ինչոր բան ասել ավելին:",
|
||||
"liveStreaming": "Ուղիղ Հեռարձակում",
|
||||
|
@ -241,20 +253,25 @@
|
|||
"stopRecordingWarning": "Վստա՞հ եք որ ցանկանում եք կանգնացնել ձայնագրումը",
|
||||
"stopLiveStreaming": "Կանգնացնել ուղիղ հեռարձակումը:",
|
||||
"stopRecording": "Կանգնացնել ձայնագրումը",
|
||||
"doNotShowWarningAgain": "",
|
||||
"permissionDenied": "",
|
||||
"screenSharingPermissionDeniedError": "",
|
||||
"micErrorPresent": "",
|
||||
"cameraErrorPresent": "",
|
||||
"cameraUnsupportedResolutionError": "",
|
||||
"cameraUnknownError": "",
|
||||
"cameraPermissionDeniedError": "",
|
||||
"cameraNotFoundError": "",
|
||||
"cameraConstraintFailedError": "",
|
||||
"micUnknownError": "",
|
||||
"micPermissionDeniedError": "",
|
||||
"micNotFoundError": "",
|
||||
"micConstraintFailedError": ""
|
||||
"doNotShowWarningAgain": "Այլևս ցույց չտալ այս նախազգուշական էջը",
|
||||
"permissionDenied": "Թույլատվությունը արգելված է",
|
||||
"screenSharingPermissionDeniedError": "Դուք չունեք թույլտվություն կիսվել Ձեր էկրանով",
|
||||
"micErrorPresent": "Տեղի է ունեցել սխալ Ձեր խոսափողին միանալիս",
|
||||
"cameraErrorPresent": "Սխալ տեսախցիկին միանալիս",
|
||||
"cameraUnsupportedResolutionError": "Ձեր տեսախցիկը չունի պահանջվող վիդեո-չափ",
|
||||
"cameraUnknownError": "Չի կարող օգտագործվել տեսախցիկը անհայտ պատճառով",
|
||||
"cameraPermissionDeniedError": "Ձեզ թույլտվրված չէ օգտագործել Ձեր տեսախցիկը: Դուք կարող եք միացած մնալ համաժողովին, սակայն մյուսները չեն տեսնի ձեզ. Օգտագործեք տեսախցիկի կոճակը խնդիրը կարգավորելու համար",
|
||||
"cameraNotFoundError": "Տեսախցիկ չի գտնվել",
|
||||
"cameraConstraintFailedError": "Ձեր տեսախցիկը չի համապատասխանում որոշ խոչընդոտների",
|
||||
"micUnknownError": "Չի կարող օգտագործվել տեսախցիկը անհայտ պատճառով",
|
||||
"micPermissionDeniedError": "Ձեզ թույլտվրված չէ օգտագործել Ձեր խոսափողը: Դուք կարող եք միացած մնալ համաժողովին, սակայն մյուսները չեն լսի ձեզ. Օգտագործեք խոսափողի կոճակը խնդիրը կարգավորելու համար",
|
||||
"micNotFoundError": "Խոսափող չի գտնվել",
|
||||
"micConstraintFailedError": "Ձեր խոսափողը չի բավարարել պահանջվող խոչընդոտներից մի քանիսը ",
|
||||
"micNotSendingData": "Մենք չեն կարողանում միանալ Ձեր խոսափողին: Խնդրում ենք ընտրել մեկ այլ սարք կարգավորումների ցանկից կամ փորձեք վերսկսել ծրագիրը",
|
||||
"cameraNotSendingData": "Մենք չեն կարողանում միանալ Ձեր տեսախցիկին: Խնդրում ենք ստուգեք թե արդյոք մեկ ուրիշ սարք չի օգտագործում այն կամ ընտրեք մեկ այլ սարք կարգավորումների ցանկից կամ փորձեք վերսկսել ծրագիրը:",
|
||||
"goToStore": "Գնալ դեպի վեբ խանութ",
|
||||
"externalInstallationTitle": "Ընդլայնում է պահանջվում:",
|
||||
"externalInstallationMsg": "Չհաջողվեց տեղադրել էկրանի ցուցադրման ընդլայնումը"
|
||||
},
|
||||
"email": {
|
||||
"sharedKey": [
|
||||
|
@ -298,8 +315,8 @@
|
|||
"off": "Ձայնագրությունը կանգնացված է",
|
||||
"failedToStart": "Ձայնագրությունը ստացվեց սկսել",
|
||||
"buttonTooltip": "Սկսել / կանգնացնել ձայնագրությունը",
|
||||
"error": "",
|
||||
"unavailable": ""
|
||||
"error": "Ձայնագրությյունը չստացվեց: Փորձեք կրկին",
|
||||
"unavailable": "Ձայնագրության ծառայությունը ներկայումս անհասանելի է: Խնդրում եմ փորձեք մի փոքր ուշ:"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"pending": "Սկսում ենք Ուղիղ Հեռարձակումը",
|
||||
|
@ -309,7 +326,7 @@
|
|||
"failedToStart": "Ուղիղ հեռարձակումը չստացվեց սկսել",
|
||||
"buttonTooltip": "Սկսել / կանգնեցնել ուղիղ հեռարձակումը",
|
||||
"streamIdRequired": "Խնդրում ենք լրացնել հոսքի ID-ն, որպեսզի կսկսի հեռարձակումը:",
|
||||
"error": "",
|
||||
"busy": ""
|
||||
"error": "Ուղիղ հեռարձակումը չստացվեց: Փորձեք կրկին",
|
||||
"busy": "Բոլոր ձայնագրիչները ներկայումս զբաղված են: Խնդրում ենք փորձեք մի փոքր ուշ:"
|
||||
}
|
||||
}
|
|
@ -1,39 +1,37 @@
|
|||
{
|
||||
"contactlist": "Lista de contactes",
|
||||
"contactlist": "Al telefòn",
|
||||
"connectionsettings": "Paramètres de connexion",
|
||||
"poweredby": "Produit per",
|
||||
"downloadlogs": "Telecargament dels logs",
|
||||
"feedback": "Donatz-nos vòstre vejaire",
|
||||
"roomUrlDefaultMsg": "Vòstra conferéncia es en cors de creacion...",
|
||||
"participant": "Participant",
|
||||
"me": "ieu",
|
||||
"speaker": "Nautparlaire",
|
||||
"raisedHand": "",
|
||||
"raisedHand": "Volriatz charrar",
|
||||
"defaultNickname": "ex. Joan Delpuèch",
|
||||
"defaultLink": "ex. __url__",
|
||||
"calling": "",
|
||||
"callingName": "__name__",
|
||||
"userMedia": {
|
||||
"react-nativeGrantPermissions": "",
|
||||
"chromeGrantPermissions": "",
|
||||
"androidGrantPermissions": "",
|
||||
"firefoxGrantPermissions": "",
|
||||
"operaGrantPermissions": "",
|
||||
"iexplorerGrantPermissions": "",
|
||||
"safariGrantPermissions": "",
|
||||
"nwjsGrantPermissions": ""
|
||||
"react-nativeGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>Autorizar</i></b>",
|
||||
"chromeGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>Autorizar</i></b>",
|
||||
"androidGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>Autorizar</i></b>",
|
||||
"firefoxGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>Partejar l'aparelh seleccionat</i></b>",
|
||||
"operaGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>Autorizar</i></b>",
|
||||
"iexplorerGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>OK</i></b>",
|
||||
"safariGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn en butant sul boton <b><i>OK</i></b>",
|
||||
"nwjsGrantPermissions": "Mercés de donar las permissions d'utilizar vòstra camerà e vòstre microfòn"
|
||||
},
|
||||
"keyboardShortcuts": {
|
||||
"keyboardShortcuts": "",
|
||||
"raiseHand": "",
|
||||
"pushToTalk": "",
|
||||
"toggleScreensharing": "",
|
||||
"toggleFilmstrip": "",
|
||||
"toggleShortcuts": "",
|
||||
"focusLocal": "",
|
||||
"focusRemote": "",
|
||||
"toggleChat": "",
|
||||
"mute": "",
|
||||
"videoMute": ""
|
||||
"keyboardShortcuts": "Acorchis de clavièr",
|
||||
"raiseHand": "Demandar a parlar.",
|
||||
"pushToTalk": "Butar per parlar",
|
||||
"toggleScreensharing": "Caplevar entre camerà e partatge d'ecran",
|
||||
"toggleFilmstrip": "Mostrar o escondre la vidèo",
|
||||
"toggleShortcuts": "Afichar o amagar aiceste menú d'ajuda",
|
||||
"focusLocal": "Focus sus la vidèo locala.",
|
||||
"focusRemote": "Focus sus una de las vidèas aluènhadas.",
|
||||
"toggleChat": "Dubrir o tampar lo panèl de conversacion.",
|
||||
"mute": "Activar o desactivar lo microfòn.",
|
||||
"videoMute": "Arrestar o lançar la vidèo locala."
|
||||
},
|
||||
"welcomepage": {
|
||||
"go": "Crear",
|
||||
|
@ -92,12 +90,14 @@
|
|||
"sharedVideoMutedPopup": "Vòstra vidèo es estada mesa en mut<br/>per que poscatz parlar als autres participants.",
|
||||
"micMutedPopup": "Vòstre microfòn es estat desactivat per fin que <br/>poscatz profeitar plenament de vòstra vidèo partejada.",
|
||||
"unableToUnmutePopup": "Podètz pas reactivar vòstre microfòn pendent que la vidèo partejada es activada.",
|
||||
"cameraDisabled": "",
|
||||
"micDisabled": ""
|
||||
"cameraDisabled": "La camerà es pas disponibla",
|
||||
"micDisabled": "Lo microfòn es pas disponible",
|
||||
"filmstrip": "",
|
||||
"raiseHand": "Demandar la paraula"
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "Dobrir / tampar lo chat",
|
||||
"filmstrip": "Mostrar / amagar ma vidèo miniatura",
|
||||
"filmstrip": "Mostrar / escondre vidèos",
|
||||
"contactlist": "Dobrir / tampar ma lista de contactes"
|
||||
},
|
||||
"chat": {
|
||||
|
@ -108,18 +108,27 @@
|
|||
"messagebox": "Sasissètz vòstre tèxte..."
|
||||
},
|
||||
"settings": {
|
||||
"title": "PARAMÈTRES",
|
||||
"title": "Paramètres",
|
||||
"update": "Mesa a jorn",
|
||||
"name": "Nom",
|
||||
"startAudioMuted": "Aviar sens son",
|
||||
"startVideoMuted": "Aviar sens vidèo",
|
||||
"selectCamera": "Seleccionatz una camèra",
|
||||
"selectMic": "Seleccionatz un microfòn",
|
||||
"selectAudioOutput": "",
|
||||
"followMe": "Activar \"me seguir\"",
|
||||
"noDevice": "",
|
||||
"noPermission": "",
|
||||
"avatarUrl": ""
|
||||
"startAudioMuted": "Tot lo mond comença sens son",
|
||||
"startVideoMuted": "Tot lo mond comença escondut",
|
||||
"selectCamera": "Camèra",
|
||||
"selectMic": "Microfòn",
|
||||
"selectAudioOutput": "Sortida àudio",
|
||||
"followMe": "Tot lo mond me sèc",
|
||||
"noDevice": "Pas cap",
|
||||
"noPermission": "La permission d'utilizar l'aparelh es pas estada donada",
|
||||
"cameraAndMic": "Camèra e microfòn",
|
||||
"moderator": "MODERATOR",
|
||||
"password": "DEFINIR UN SENHAL",
|
||||
"audioVideo": "ÀUDIO E VIDÈO",
|
||||
"setPasswordLabel": "Verrolhar vòstra sala amb un senhal"
|
||||
},
|
||||
"profile": {
|
||||
"title": "PERFIL",
|
||||
"setDisplayNameLabel": "Causissètz vòstra nom",
|
||||
"setEmailLabel": "Definir vòstre corrièl per gravatar"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"editnickname": "Clicatz per modificar<br/>vòstre nom",
|
||||
|
@ -129,7 +138,7 @@
|
|||
"kick": "Exclure",
|
||||
"muted": "Mut",
|
||||
"domute": "Copar lo son",
|
||||
"flip": ""
|
||||
"flip": "Revirar"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"bitrate": "Debit :",
|
||||
|
@ -162,7 +171,7 @@
|
|||
"grantedToUnknown": "Dreits moderator acordats a $t(somebody) !",
|
||||
"muted": "Avètz començat la conversacion en mut.",
|
||||
"mutedTitle": "Sètz en mut !",
|
||||
"raisedHand": ""
|
||||
"raisedHand": "Volriá parlar."
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "Ops! Sètz estat bandit de la reünion !",
|
||||
|
@ -172,6 +181,7 @@
|
|||
"connectError": "Ops! Quicòm a trucat e la connexion a la conferéncia es impossibla.",
|
||||
"connectErrorWithMsg": "Ops! Quicòm a trucat e la connexion a la conferéncia es impossibla: __msg__",
|
||||
"connecting": "Connexion en cors",
|
||||
"copy": "Copiar",
|
||||
"error": "Error",
|
||||
"detectext": "Una error s'es produita pendent la deteccion de l'extension de partiment d'ecran.",
|
||||
"failtoinstall": "Fracàs de l'installacion de l'extension de partiment d'ecran",
|
||||
|
@ -183,8 +193,8 @@
|
|||
"lockMessage": "Impossible de verrolhar la conferéncia.",
|
||||
"warning": "Avertiment",
|
||||
"passwordNotSupported": "Los senhals de conferéncia son pas suportats.",
|
||||
"sorry": "O planhèm",
|
||||
"internalError": "Una error intèrna de l'aplicacion s'es produita [setRemoteDescription]",
|
||||
"internalErrorTitle": "Error intèrna",
|
||||
"internalError": "Ops ! Quicòm a pas fonccionat. L'error seguenta s'es produsida : [setRemoteDescription]",
|
||||
"unableToSwitch": "Impossible de cambiar lo flux vidèo.",
|
||||
"SLDFailure": "Ops! Quicòm a trucat e lo micro es pas estat copat! (Fracàs SLD)",
|
||||
"SRDFailure": "Ops! Quicòm a trucat e la camèra es pas estada copada! (Fracàs SRD)",
|
||||
|
@ -216,26 +226,28 @@
|
|||
"sipMsg": "Sasissètz un numèro SIP",
|
||||
"passwordCheck": "Sètz segur que volètz suprimir vòstre senhal ?",
|
||||
"passwordMsg": "Sasissètz un senhal per verrolhar la conferéncia",
|
||||
"Invite": "Convidar",
|
||||
"shareLink": "Partejatz aqueste ligam amb totas las personas que volètz convidar",
|
||||
"shareLink": "Copiatz e partejatz aqueste ligam",
|
||||
"settings1": "Configuratz vòstra conferéncia",
|
||||
"settings2": "Los participants rejonhon la conferéncia en essent muts",
|
||||
"settings3": "Escaisses requesits<br/><br/>Sasissètz un senhal per verrolhar la conferéncia :",
|
||||
"yourPassword": "vòstre senhal",
|
||||
"yourPassword": "Picatz un novèl senhal utilizaire",
|
||||
"Back": "Retorn",
|
||||
"serviceUnavailable": "Servici indisponible",
|
||||
"gracefulShutdown": "Lo servici es actualament en mantenença. Ensajatz tornamai pus tard.",
|
||||
"Yes": "Òc",
|
||||
"reservationError": "Error del sistèma de reservacion",
|
||||
"reservationErrorMsg": "Còdi d'error: __code__, messatge: __msg__",
|
||||
"password": "senhal",
|
||||
"password": "Picar lo senhal",
|
||||
"userPassword": "senhal utilizaire",
|
||||
"token": "geton",
|
||||
"tokenAuthFailed": "Fracàs de l'autentificacion amb lo servidor XMPP : geton pas valid",
|
||||
"tokenAuthFailedTitle": "Fracàs de l'autentificacion",
|
||||
"tokenAuthFailed": "O planhèm, sètz pas autorizat a rejónher l'apèl.",
|
||||
"displayNameRequired": "Sasissètz vòstre nom",
|
||||
"extensionRequired": "Extension requesida :",
|
||||
"firefoxExtensionPrompt": "Vos cal installar una extension Firefox per utilizar lo partiment d'ecran. Mercé ensajar tornamai aprèp l'installacion <a href='__url__'>dempuèi aqueste ligam</a> !",
|
||||
"feedbackQuestion": "Cossí èra vòstra conferéncia ?",
|
||||
"rateExperience": "Mercés de donar una nota à vòstra experiéncia.",
|
||||
"feedbackHelp": "Vòstres comentaris nos ajudaràn a milhorar l'experiéncia vidèo",
|
||||
"feedbackQuestion": "Contatz-nos cossí èra vòstre apèl !",
|
||||
"thankYou": "Mercé d'aver utilizat __appName__ !",
|
||||
"sorryFeedback": "Planhèm d'aprene aquò. Ne nos volètz dire mai ?",
|
||||
"liveStreaming": "Dirècte",
|
||||
|
@ -245,20 +257,25 @@
|
|||
"stopRecordingWarning": "Sètz segur que volètz arrestar l'enregistrament?",
|
||||
"stopLiveStreaming": "Arrestar lo dirècte",
|
||||
"stopRecording": "Arrestar l'enregistrament",
|
||||
"doNotShowWarningAgain": "",
|
||||
"permissionDenied": "",
|
||||
"screenSharingPermissionDeniedError": "",
|
||||
"micErrorPresent": "",
|
||||
"cameraErrorPresent": "",
|
||||
"cameraUnsupportedResolutionError": "",
|
||||
"cameraUnknownError": "",
|
||||
"cameraPermissionDeniedError": "",
|
||||
"cameraNotFoundError": "",
|
||||
"cameraConstraintFailedError": "",
|
||||
"micUnknownError": "",
|
||||
"micPermissionDeniedError": "",
|
||||
"micNotFoundError": "",
|
||||
"micConstraintFailedError": ""
|
||||
"doNotShowWarningAgain": "Afichar pas mai aqueste avertiment",
|
||||
"permissionDenied": "Permission Refusada",
|
||||
"screenSharingPermissionDeniedError": "Vos cal autorizar lo partatge de vòstre ecran.",
|
||||
"micErrorPresent": "I a agut una error pendent la connexion al microfòn.",
|
||||
"cameraErrorPresent": "I a agut una error pendent la connexion a la camerà.",
|
||||
"cameraUnsupportedResolutionError": "Vòstra camerà pren pas en carga la resolucion vidèo que cal.",
|
||||
"cameraUnknownError": "Impossible d'emplegar la camerà per una rason desconeguda.",
|
||||
"cameraPermissionDeniedError": "La camèra es pas estada trobada.",
|
||||
"cameraNotFoundError": "La camèra es pas estada trobada.",
|
||||
"cameraConstraintFailedError": "Vòstra camerà satisfà pas totas las constrentas necessàrias.",
|
||||
"micUnknownError": "Impossible d'utilizar lo microfòn per una rason desconeguda.",
|
||||
"micPermissionDeniedError": "Avètz pas donat l'autorizacion d'utilizar vòstre microfòn. Podètz encara participar a la conferéncia mai los demai vos ausiràn pas. Utilizatz lo boton del microfòn dins la barra d'adreça per resòlvre aquò.",
|
||||
"micNotFoundError": "Lo microfòn es pas estat trobat.",
|
||||
"micConstraintFailedError": "Vòstre microfòn satisfà pas totas las constrentas necessàrias.",
|
||||
"micNotSendingData": "Podèm pas aver l'accès a vòstre microfòn. Mercés de ne causir un autre dins lo menú de paramètres o ensajatz de tornar dubrir l'aplicacion.",
|
||||
"cameraNotSendingData": "Podèm pas aver l'accès a vòstra camèra. Mercés de verificar se una autra aplicacion es pas a l'utilizar, causissètz una autra camèra dins lo menú de paramètres o ensajatz de tornar dubrir l'aplicacion.",
|
||||
"goToStore": "Anatz sul webstore",
|
||||
"externalInstallationTitle": "Extension requesida :",
|
||||
"externalInstallationMsg": "Avètz d'installar nòstra extension de partiment d'ecran."
|
||||
},
|
||||
"email": {
|
||||
"sharedKey": [
|
||||
|
@ -306,8 +323,8 @@
|
|||
"off": "Enregistrament arrestar",
|
||||
"failedToStart": "L'enregistrament n'as pas réussi a démarrer",
|
||||
"buttonTooltip": "Aviar / arrestar l'enregistrament",
|
||||
"error": "",
|
||||
"unavailable": ""
|
||||
"error": "Fracàs de l'enregistrament. Mercés de tornar ensajar.",
|
||||
"unavailable": "Lo servici d'enregistrament es actualament indisponible. Mercés de tornar ensajar mai tard."
|
||||
},
|
||||
"liveStreaming": {
|
||||
"pending": "Començar lo dirècte...",
|
||||
|
@ -317,7 +334,7 @@
|
|||
"failedToStart": "Lo dirècte a pas capitat de s'aviar",
|
||||
"buttonTooltip": "Aviar / arrestar lo dirècte",
|
||||
"streamIdRequired": "Mercé de completar lo stream id per aviar lo dirècte.",
|
||||
"error": "",
|
||||
"busy": ""
|
||||
"error": "Fracàs de la transmission en dirècte. Mercés de tornar ensajar.",
|
||||
"busy": "Tots los enresgistraires son ocupats. Mercés de tornar ensajar mai tard."
|
||||
}
|
||||
}
|
|
@ -1,9 +1,13 @@
|
|||
{
|
||||
"contactlist": "On Call",
|
||||
"contactlist": "Participants",
|
||||
"addParticipants": "Add Participants",
|
||||
"roomLocked": "Callers must enter a password",
|
||||
"roomUnlocked": "Anyone with the link can join",
|
||||
"passwordSetRemotely": "set by another participant",
|
||||
"connectionsettings": "Connection Settings",
|
||||
"poweredby": "powered by",
|
||||
"feedback": "Give us your feedback",
|
||||
"roomUrlDefaultMsg": "Your conference is currently being created...",
|
||||
"inviteUrlDefaultMsg": "Your conference is currently being created...",
|
||||
"me": "me",
|
||||
"speaker": "Speaker",
|
||||
"raisedHand": "Would like to speak",
|
||||
|
@ -180,8 +184,10 @@
|
|||
"raisedHand": "Would like to speak."
|
||||
},
|
||||
"dialog": {
|
||||
"add": "Add",
|
||||
"kickMessage": "Ouch! You have been kicked out of the meet!",
|
||||
"popupError": "Your browser is blocking popup windows from this site. Please enable popups in your browser's security settings and try again.",
|
||||
"passwordErrorTitle": "Password Error",
|
||||
"passwordError": "This conversation is currently protected by a password. Only the owner of the conference can set a password.",
|
||||
"passwordError2": "This conversation isn't currently protected by a password. Only the owner of the conference can set a password.",
|
||||
"connectError": "Oops! Something went wrong and we couldn't connect to the conference.",
|
||||
|
@ -189,6 +195,7 @@
|
|||
"connecting": "Connecting",
|
||||
"copy": "Copy",
|
||||
"error": "Error",
|
||||
"addPassword": "Add Password",
|
||||
"detectext": "Error when trying to detect desktopsharing extension.",
|
||||
"failtoinstall": "Failed to install desktop sharing extension",
|
||||
"failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.",
|
||||
|
@ -205,10 +212,13 @@
|
|||
"SLDFailure": "Oops! Something went wrong and we failed to mute! (SLD Failure)",
|
||||
"SRDFailure": "Oops! Something went wrong and we failed to stop video! (SRD Failure)",
|
||||
"oops": "Oops!",
|
||||
"currentPassword": "The current password is",
|
||||
"passwordLabel": "Password",
|
||||
"defaultError": "There was some kind of error",
|
||||
"passwordRequired": "Password required",
|
||||
"Ok": "Ok",
|
||||
"Remove": "Remove",
|
||||
"removePassword": "Remove password",
|
||||
"shareVideoTitle": "Share a video",
|
||||
"shareVideoLinkError": "Please provide a correct youtube link.",
|
||||
"removeSharedVideoTitle": "Remove shared video",
|
||||
|
@ -218,6 +228,7 @@
|
|||
"WaitForHostMsg": "The conference <b>__room__ </b> has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.",
|
||||
"IamHost": "I am the host",
|
||||
"Cancel": "Cancel",
|
||||
"Submit": "Submit",
|
||||
"retry": "Retry",
|
||||
"logoutTitle" : "Logout",
|
||||
"logoutQuestion" : "Are you sure you want to logout and stop the conference?",
|
||||
|
@ -231,7 +242,6 @@
|
|||
"Dial": "Dial",
|
||||
"sipMsg": "Enter SIP number",
|
||||
"passwordCheck": "Are you sure you would like to remove your password?",
|
||||
"Remove": "Remove",
|
||||
"passwordMsg": "Set a password to lock your room",
|
||||
"shareLink": "Copy and share this link",
|
||||
"settings1": "Configure your conference",
|
||||
|
|
121
modules/UI/UI.js
121
modules/UI/UI.js
|
@ -4,7 +4,6 @@ var UI = {};
|
|||
import Chat from "./side_pannels/chat/Chat";
|
||||
import Toolbar from "./toolbars/Toolbar";
|
||||
import ToolbarToggler from "./toolbars/ToolbarToggler";
|
||||
import ContactList from "./side_pannels/contactlist/ContactList";
|
||||
import Avatar from "./avatar/Avatar";
|
||||
import SideContainerToggler from "./side_pannels/SideContainerToggler";
|
||||
import UIUtil from "./util/UIUtil";
|
||||
|
@ -29,7 +28,6 @@ UI.messageHandler = require("./util/MessageHandler");
|
|||
var messageHandler = UI.messageHandler;
|
||||
var JitsiPopover = require("./util/JitsiPopover");
|
||||
var Feedback = require("./feedback/Feedback");
|
||||
|
||||
import FollowMe from "../FollowMe";
|
||||
|
||||
var eventEmitter = new EventEmitter();
|
||||
|
@ -242,7 +240,7 @@ UI.showChatError = function (err, msg) {
|
|||
* @param {string} displayName new nickname
|
||||
*/
|
||||
UI.changeDisplayName = function (id, displayName) {
|
||||
ContactList.onDisplayNameChange(id, displayName);
|
||||
UI.ContactList.onDisplayNameChange(id, displayName);
|
||||
VideoLayout.onDisplayNameChanged(id, displayName);
|
||||
|
||||
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
|
||||
|
@ -292,14 +290,16 @@ UI.initConference = function () {
|
|||
// "https:" + "//" + "example.com:8888" + "/SomeConference1245"
|
||||
var inviteURL = window.location.protocol + "//" +
|
||||
window.location.host + window.location.pathname;
|
||||
Toolbar.updateRoomUrl(inviteURL);
|
||||
|
||||
this.emitEvent(UIEvents.INVITE_URL_INITIALISED, inviteURL);
|
||||
|
||||
// Clean up the URL displayed by the browser
|
||||
if (window.history && typeof window.history.replaceState === 'function') {
|
||||
window.history.replaceState({}, document.title, inviteURL);
|
||||
}
|
||||
|
||||
// Add myself to the contact list.
|
||||
ContactList.addContact(id, true);
|
||||
UI.ContactList.addContact(id, true);
|
||||
|
||||
// Update default button states before showing the toolbar
|
||||
// if local role changes buttons state will be again updated.
|
||||
|
@ -345,7 +345,6 @@ UI.mucJoined = function () {
|
|||
*/
|
||||
UI.handleToggleFilmStrip = () => {
|
||||
UI.toggleFilmStrip();
|
||||
VideoLayout.resizeVideoArea(true, false);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -471,8 +470,6 @@ UI.start = function () {
|
|||
}
|
||||
VideoLayout.resizeVideoArea(true, true);
|
||||
|
||||
ContactList.init(eventEmitter);
|
||||
|
||||
bindEvents();
|
||||
sharedVideoManager = new SharedVideoManager(eventEmitter);
|
||||
if (!interfaceConfig.filmStripOnly) {
|
||||
|
@ -609,7 +606,7 @@ UI.addUser = function (user) {
|
|||
var id = user.getId();
|
||||
var displayName = user.getDisplayName();
|
||||
UI.hideRingOverLay();
|
||||
ContactList.addContact(id);
|
||||
UI.ContactList.addContact(id);
|
||||
|
||||
messageHandler.notify(
|
||||
displayName,'notify.somebody', 'connected', 'notify.connected'
|
||||
|
@ -636,7 +633,7 @@ UI.addUser = function (user) {
|
|||
* @param {string} displayName user nickname
|
||||
*/
|
||||
UI.removeUser = function (id, displayName) {
|
||||
ContactList.removeContact(id);
|
||||
UI.ContactList.removeContact(id);
|
||||
|
||||
messageHandler.notify(
|
||||
displayName,'notify.somebody', 'disconnected', 'notify.disconnected'
|
||||
|
@ -729,6 +726,7 @@ UI.toggleSmileys = function () {
|
|||
UI.toggleFilmStrip = function () {
|
||||
var self = FilmStrip;
|
||||
self.toggleFilmStrip.apply(self, arguments);
|
||||
VideoLayout.resizeVideoArea(true, false);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -786,28 +784,33 @@ UI.connectionIndicatorShowMore = function(id) {
|
|||
// FIXME check if someone user this
|
||||
UI.showLoginPopup = function(callback) {
|
||||
console.log('password is required');
|
||||
var message = '<h2 data-i18n="dialog.passwordRequired">';
|
||||
message += APP.translation.translateString(
|
||||
"dialog.passwordRequired");
|
||||
message += '</h2>' +
|
||||
'<input name="username" type="text" ' +
|
||||
'placeholder="user@domain.net" autofocus>' +
|
||||
'<input name="password" ' +
|
||||
'type="password" data-i18n="[placeholder]dialog.userPassword"' +
|
||||
' placeholder="user password">';
|
||||
messageHandler.openTwoButtonDialog(null, null, null, message,
|
||||
true,
|
||||
"dialog.Ok",
|
||||
function (e, v, m, f) {
|
||||
if (v) {
|
||||
if (f.username && f.password) {
|
||||
callback(f.username, f.password);
|
||||
}
|
||||
}
|
||||
},
|
||||
null, null, ':input:first'
|
||||
let titleKey = "dialog.passwordRequired";
|
||||
let titleString = APP.translation.translateString(titleKey);
|
||||
|
||||
let message = (
|
||||
`<input name="username" type="text"
|
||||
placeholder="user@domain.net" autofocus>
|
||||
<input name="password" type="password"
|
||||
data-i18n="[placeholder]dialog.userPassword"
|
||||
placeholder="user password">`
|
||||
);
|
||||
|
||||
let submitFunction = (e, v, m, f) => {
|
||||
if (v) {
|
||||
if (f.username && f.password) {
|
||||
callback(f.username, f.password);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
titleString,
|
||||
msgString: message,
|
||||
leftButtonKey: 'dialog.Ok',
|
||||
submitFunction,
|
||||
focus: ':input:first'
|
||||
});
|
||||
};
|
||||
|
||||
UI.askForNickname = function () {
|
||||
|
@ -888,7 +891,7 @@ UI.dockToolbar = function (isDock) {
|
|||
*/
|
||||
function changeAvatar(id, avatarUrl) {
|
||||
VideoLayout.changeUserAvatar(id, avatarUrl);
|
||||
ContactList.changeUserAvatar(id, avatarUrl);
|
||||
UI.ContactList.changeUserAvatar(id, avatarUrl);
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
Profile.changeAvatar(avatarUrl);
|
||||
}
|
||||
|
@ -1054,18 +1057,6 @@ UI.markVideoInterrupted = function (interrupted) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark room as locked or not.
|
||||
* @param {boolean} locked if room is locked.
|
||||
*/
|
||||
UI.markRoomLocked = function (locked) {
|
||||
if (locked) {
|
||||
Toolbar.lockLockButton();
|
||||
} else {
|
||||
Toolbar.unlockLockButton();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add chat message.
|
||||
* @param {string} from user id
|
||||
|
@ -1254,24 +1245,27 @@ UI.showExtensionRequiredDialog = function (url) {
|
|||
* @param url {string} the url of the extension.
|
||||
*/
|
||||
UI.showExtensionExternalInstallationDialog = function (url) {
|
||||
messageHandler.openTwoButtonDialog(
|
||||
"dialog.externalInstallationTitle",
|
||||
null,
|
||||
"dialog.externalInstallationMsg",
|
||||
null,
|
||||
true,
|
||||
"dialog.goToStore",
|
||||
function(e,v) {
|
||||
if (v) {
|
||||
e.preventDefault();
|
||||
eventEmitter.emit(UIEvents.OPEN_EXTENSION_STORE, url);
|
||||
}
|
||||
},
|
||||
function () {},
|
||||
function () {
|
||||
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
||||
let submitFunction = function(e,v){
|
||||
if (v) {
|
||||
e.preventDefault();
|
||||
eventEmitter.emit(UIEvents.OPEN_EXTENSION_STORE, url);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let closeFunction = function () {
|
||||
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
||||
};
|
||||
|
||||
messageHandler.openTwoButtonDialog({
|
||||
titleKey: 'dialog.externalInstallationTitle',
|
||||
titleString: '',
|
||||
msgKey: 'dialog.externalInstallationMsg',
|
||||
msgString: '',
|
||||
leftButtonKey: 'dialog.goToStore',
|
||||
submitFunction,
|
||||
loadedFunction: $.noop,
|
||||
closeFunction
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -1518,7 +1512,12 @@ UI.hideUserMediaPermissionsGuidanceOverlay = function () {
|
|||
* Shows or hides the keyboard shortcuts panel, depending on the current state.'
|
||||
*/
|
||||
UI.toggleKeyboardShortcutsPanel = function() {
|
||||
$('#keyboard-shortcuts').toggle();
|
||||
let titleKey = 'keyboardShortcuts.keyboardShortcuts';
|
||||
let title = APP.translation.translateString(titleKey);
|
||||
let msg = $('#keyboard-shortcuts').html();
|
||||
let buttons = { Close: true };
|
||||
|
||||
messageHandler.openDialog(title, msg, true, buttons);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
/* global APP, JitsiMeetJS */
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
/**
|
||||
* Show dialog which asks user for new password for the conference.
|
||||
* @returns {Promise<string>} password or nothing if user canceled
|
||||
*/
|
||||
function askForNewPassword () {
|
||||
let passMsg = APP.translation.generateTranslationHTML("dialog.passwordMsg");
|
||||
let yourPassMsg = APP.translation.translateString("dialog.yourPassword");
|
||||
let msg = `
|
||||
<h2>${passMsg}</h2>
|
||||
<input name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.yourPassword"
|
||||
placeholder="${yourPassMsg}" autofocus>
|
||||
`;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
msg, false, "dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
if (v && f.lockKey) {
|
||||
resolve(UIUtil.escapeHtml(f.lockKey));
|
||||
}
|
||||
else {
|
||||
reject(APP.UI.messageHandler.CANCEL);
|
||||
}
|
||||
},
|
||||
null, null, 'input:first'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dialog which asks for required conference password.
|
||||
* @returns {Promise<string>} password or nothing if user canceled
|
||||
*/
|
||||
function askForPassword () {
|
||||
let passRequiredMsg = APP.translation.translateString(
|
||||
"dialog.passwordRequired"
|
||||
);
|
||||
let passMsg = APP.translation.translateString("dialog.password");
|
||||
let msg = `
|
||||
<h2 data-i18n="dialog.passwordRequired">${passRequiredMsg}</h2>
|
||||
<input name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.password"
|
||||
placeholder="${passMsg}" autofocus>
|
||||
`;
|
||||
return new Promise(function (resolve, reject) {
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, null, null, msg,
|
||||
true, "dialog.Ok",
|
||||
function () {}, null,
|
||||
function (e, v, m, f) {
|
||||
if (v && f.lockKey) {
|
||||
resolve(UIUtil.escapeHtml(f.lockKey));
|
||||
} else {
|
||||
reject(APP.UI.messageHandler.CANCEL);
|
||||
}
|
||||
},
|
||||
':input:first'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dialog which asks if user want remove password from the conference.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function askToUnlock () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, null, "dialog.passwordCheck",
|
||||
null, false, "dialog.Remove",
|
||||
function (e, v) {
|
||||
if (v) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(APP.UI.messageHandler.CANCEL);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notification that user cannot set password for the conference
|
||||
* because server doesn't support that.
|
||||
*/
|
||||
function notifyPasswordNotSupported () {
|
||||
console.warn('room passwords not supported');
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.warning", "dialog.passwordNotSupported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notification that setting password for the conference failed.
|
||||
* @param {Error} err error
|
||||
*/
|
||||
function notifyPasswordFailed(err) {
|
||||
console.warn('setting password failed', err);
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.lockTitle", "dialog.lockMessage");
|
||||
}
|
||||
|
||||
const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
|
||||
/**
|
||||
* Create new RoomLocker for the conference.
|
||||
* It allows to set or remove password for the conference,
|
||||
* or ask for required password.
|
||||
* @returns {RoomLocker}
|
||||
*/
|
||||
export default function createRoomLocker (room) {
|
||||
let password;
|
||||
let dialog = null;
|
||||
|
||||
/**
|
||||
* If the room was locked from someone other than us, we indicate it with
|
||||
* this property in order to have correct roomLocker state of isLocked.
|
||||
* @type {boolean} whether room is locked, but not from us.
|
||||
*/
|
||||
let lockedElsewhere = false;
|
||||
|
||||
function lock (newPass) {
|
||||
return room.lock(newPass).then(function () {
|
||||
password = newPass;
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
if (err === ConferenceErrors.PASSWORD_NOT_SUPPORTED) {
|
||||
notifyPasswordNotSupported();
|
||||
} else {
|
||||
notifyPasswordFailed(err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @class RoomLocker
|
||||
*/
|
||||
return {
|
||||
get isLocked () {
|
||||
return !!password || lockedElsewhere;
|
||||
},
|
||||
|
||||
get password () {
|
||||
return password;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets that the room is locked from another user, not us.
|
||||
* @param {boolean} value locked/unlocked state
|
||||
*/
|
||||
set lockedElsewhere (value) {
|
||||
lockedElsewhere = value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether room is locked from someone else.
|
||||
* @returns {boolean} whether room is not locked locally,
|
||||
* but it is still locked.
|
||||
*/
|
||||
get lockedElsewhere () {
|
||||
return lockedElsewhere;
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows to remove password from the conference (asks user first).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
askToUnlock () {
|
||||
return askToUnlock().then(
|
||||
() => { return lock(); }
|
||||
).then(function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.lock.disabled');
|
||||
}).catch(
|
||||
reason => {
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows to set password for the conference.
|
||||
* It asks user for new password and locks the room.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
askToLock () {
|
||||
return askForNewPassword().then(
|
||||
newPass => { return lock(newPass);}
|
||||
).then(function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.lock.enabled');
|
||||
}).catch(
|
||||
reason => {
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Asks user for required conference password.
|
||||
*/
|
||||
requirePassword () {
|
||||
return askForPassword().then(
|
||||
newPass => { password = newPass; }
|
||||
).catch(
|
||||
reason => {
|
||||
// user canceled, no pass was entered.
|
||||
// clear, as if we use the same instance several times
|
||||
// pass stays between attempts
|
||||
password = null;
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show notification that to set/remove password user must be moderator.
|
||||
*/
|
||||
notifyModeratorRequired () {
|
||||
if (dialog)
|
||||
return;
|
||||
|
||||
let closeCallback = function () {
|
||||
dialog = null;
|
||||
};
|
||||
|
||||
if (this.isLocked) {
|
||||
dialog = APP.UI.messageHandler
|
||||
.openMessageDialog(null, "dialog.passwordError",
|
||||
null, null, closeCallback);
|
||||
} else {
|
||||
dialog = APP.UI.messageHandler
|
||||
.openMessageDialog(null, "dialog.passwordError2",
|
||||
null, null, closeCallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/* global $, APP, JitsiMeetJS */
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import FeedabckWindow from "./FeedbackWindow";
|
||||
import FeedbackWindow from "./FeedbackWindow";
|
||||
|
||||
/**
|
||||
* Shows / hides the feedback button.
|
||||
|
@ -49,7 +49,7 @@ var Feedback = {
|
|||
|
||||
_showFeedbackButton(this.enabled);
|
||||
|
||||
this.window = new FeedabckWindow({});
|
||||
this.window = new FeedbackWindow();
|
||||
|
||||
$("#feedbackButton").click(Feedback.openFeedbackWindow);
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
/* global $, APP, interfaceConfig, AJS */
|
||||
/* global $, APP, interfaceConfig */
|
||||
|
||||
const selector = '#aui-feedback-dialog';
|
||||
const labels = {
|
||||
1: 'Very Bad',
|
||||
2: 'Bad',
|
||||
3: 'Average',
|
||||
4: 'Good',
|
||||
5: 'Very Good'
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the appropriate css class for the given number of stars, to
|
||||
|
@ -9,12 +15,18 @@ const selector = '#aui-feedback-dialog';
|
|||
* @param starCount the number of stars, for which to toggle the css class
|
||||
*/
|
||||
function toggleStars(starCount) {
|
||||
let labelEl = $('#starLabel');
|
||||
let label = starCount >= 0 ?
|
||||
labels[starCount + 1] :
|
||||
'';
|
||||
|
||||
$('#stars > a').each(function(index, el) {
|
||||
if (index <= starCount) {
|
||||
el.classList.add("starHover");
|
||||
} else
|
||||
el.classList.remove("starHover");
|
||||
});
|
||||
labelEl.text(label);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,63 +35,51 @@ function toggleStars(starCount) {
|
|||
* @returns {string} the contructed html string
|
||||
*/
|
||||
function createRateFeedbackHTML() {
|
||||
let rateExperience
|
||||
= APP.translation.translateString('dialog.rateExperience'),
|
||||
feedbackHelp = APP.translation.translateString('dialog.feedbackHelp');
|
||||
let feedbackHelp = APP.translation.translateString('dialog.feedbackHelp');
|
||||
|
||||
let starClassName = (interfaceConfig.ENABLE_FEEDBACK_ANIMATION)
|
||||
? "icon-star shake-rotate"
|
||||
: "icon-star";
|
||||
? "icon-star-full shake-rotate"
|
||||
: "icon-star-full";
|
||||
|
||||
return `
|
||||
<div class="aui-dialog2-content feedback__content">
|
||||
<form action="javascript:false;" onsubmit="return false;">
|
||||
<div class="feedback__rating">
|
||||
<h2>${ rateExperience }</h2>
|
||||
<p class="star-label"> </p>
|
||||
<div id="stars" class="feedback-stars">
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
</div>
|
||||
<p> </p>
|
||||
<p>${ feedbackHelp }</p>
|
||||
<form id="feedbackForm"
|
||||
action="javascript:false;" onsubmit="return false;">
|
||||
<div class="rating">
|
||||
<div class="star-label">
|
||||
<p id="starLabel"> </p>
|
||||
</div>
|
||||
<textarea id="feedbackTextArea" rows="10" cols="40" autofocus>
|
||||
</textarea>
|
||||
</form>
|
||||
<footer class="aui-dialog2-footer feedback__footer">
|
||||
<div class="aui-dialog2-footer-actions">
|
||||
<button
|
||||
id="dialog-close-button"
|
||||
class="aui-button aui-button_close">Close</button>
|
||||
<button
|
||||
id="dialog-submit-button"
|
||||
class="aui-button aui-button_submit">Submit</button>
|
||||
<div id="stars" class="feedback-stars">
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
<a class="star-btn">
|
||||
<i class=${ starClassName }></i>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
`;
|
||||
</div>
|
||||
<div class="details">
|
||||
<textarea id="feedbackTextArea" class="input-control__input"
|
||||
placeholder="${ feedbackHelp }"></textarea>
|
||||
</div>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for Rate Feedback
|
||||
* Feedback is loaded callback
|
||||
* Calls when Modal window is in DOM
|
||||
*
|
||||
* @param Feedback
|
||||
*/
|
||||
let onLoadRateFunction = function (Feedback) {
|
||||
let onLoadFunction = function (Feedback) {
|
||||
$('#stars > a').each((index, el) => {
|
||||
el.onmouseover = function(){
|
||||
toggleStars(index);
|
||||
|
@ -89,6 +89,7 @@ let onLoadRateFunction = function (Feedback) {
|
|||
};
|
||||
el.onclick = function(){
|
||||
Feedback.feedbackScore = index + 1;
|
||||
Feedback.setFeedbackMessage();
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -97,101 +98,88 @@ let onLoadRateFunction = function (Feedback) {
|
|||
toggleStars(Feedback.feedbackScore - 1);
|
||||
}
|
||||
|
||||
if (Feedback.feedbackText && Feedback.feedbackText.length > 0)
|
||||
$('#feedbackTextArea').text(Feedback.feedbackText);
|
||||
|
||||
let submitBtn = Feedback.$el.find('#dialog-submit-button');
|
||||
let closeBtn = Feedback.$el.find('#dialog-close-button');
|
||||
|
||||
if (submitBtn && submitBtn.length) {
|
||||
submitBtn.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
Feedback.onFeedbackSubmitted();
|
||||
});
|
||||
}
|
||||
if (closeBtn && closeBtn.length) {
|
||||
closeBtn.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
Feedback.hide();
|
||||
});
|
||||
}
|
||||
if (Feedback.feedbackMessage && Feedback.feedbackMessage.length > 0)
|
||||
$('#feedbackTextArea').text(Feedback.feedbackMessage);
|
||||
|
||||
$('#feedbackTextArea').focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* On Feedback Submitted callback
|
||||
*
|
||||
* @param Feedback
|
||||
*/
|
||||
function onFeedbackSubmitted(Feedback) {
|
||||
let form = $('#feedbackForm');
|
||||
let message = form.find('textarea').val();
|
||||
|
||||
APP.conference.sendFeedback(
|
||||
Feedback.feedbackScore,
|
||||
message);
|
||||
|
||||
// TODO: make sendFeedback return true or false.
|
||||
Feedback.submitted = true;
|
||||
|
||||
//Remove history is submitted
|
||||
Feedback.feedbackScore = -1;
|
||||
Feedback.feedbackMessage = '';
|
||||
Feedback.onHide();
|
||||
}
|
||||
|
||||
/**
|
||||
* On Feedback Closed callback
|
||||
*
|
||||
* @param Feedback
|
||||
*/
|
||||
function onFeedbackClosed(Feedback) {
|
||||
Feedback.onHide();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Dialog
|
||||
*
|
||||
*/
|
||||
export default class Dialog {
|
||||
|
||||
constructor(options) {
|
||||
constructor() {
|
||||
this.feedbackScore = -1;
|
||||
this.feedbackText = null;
|
||||
this.feedbackMessage = '';
|
||||
this.submitted = false;
|
||||
this.onCloseCallback = null;
|
||||
this.onCloseCallback = function() {};
|
||||
|
||||
this.states = {
|
||||
rate_feedback: {
|
||||
getHtml: createRateFeedbackHTML,
|
||||
onLoad: onLoadRateFunction
|
||||
}
|
||||
};
|
||||
this.state = options.state || 'rate_feedback';
|
||||
|
||||
this.window = AJS.dialog2(selector, {
|
||||
closeOnOutsideClick: true
|
||||
});
|
||||
this.$el = this.window.$el;
|
||||
|
||||
AJS.dialog2(selector).on("hide", function() {
|
||||
if (this.onCloseCallback) {
|
||||
this.onCloseCallback();
|
||||
this.onCloseCallback = null;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.setState();
|
||||
this.setDefoulOptions();
|
||||
}
|
||||
|
||||
setState(state) {
|
||||
let newState = state || this.state;
|
||||
setDefoulOptions() {
|
||||
var self = this;
|
||||
|
||||
let htmlStr = this.states[newState].getHtml(this);
|
||||
this.options = {
|
||||
titleKey: 'dialog.rateExperience',
|
||||
msgString: createRateFeedbackHTML(),
|
||||
loadedFunction: function() {onLoadFunction(self);},
|
||||
submitFunction: function() {onFeedbackSubmitted(self);},
|
||||
closeFunction: function() {onFeedbackClosed(self);},
|
||||
wrapperClass: 'feedback',
|
||||
size: 'medium'
|
||||
};
|
||||
}
|
||||
|
||||
this.$el.html(htmlStr);
|
||||
setFeedbackMessage() {
|
||||
let message = $('#feedbackTextArea').val();
|
||||
|
||||
this.states[newState].onLoad(this);
|
||||
this.feedbackMessage = message;
|
||||
}
|
||||
|
||||
show(cb) {
|
||||
this.setState('rate_feedback');
|
||||
if (typeof cb == 'function') {
|
||||
const options = this.options;
|
||||
if (typeof cb === 'function') {
|
||||
this.onCloseCallback = cb;
|
||||
}
|
||||
|
||||
this.window.show();
|
||||
|
||||
this.window = APP.UI.messageHandler.openTwoButtonDialog(options);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.window.hide();
|
||||
}
|
||||
|
||||
onFeedbackSubmitted() {
|
||||
let message = this.$el.find('textarea').val();
|
||||
let self = this;
|
||||
|
||||
if (message && message.length > 0) {
|
||||
self.feedbackText = message;
|
||||
}
|
||||
|
||||
APP.conference.sendFeedback(self.feedbackScore,
|
||||
self.feedbackText);
|
||||
|
||||
// TO DO: make sendFeedback return true or false.
|
||||
self.submitted = true;
|
||||
|
||||
this.hide();
|
||||
onHide() {
|
||||
this.onCloseCallback(this.feedbackScore, this.feedbackMessage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* global APP, $ */
|
||||
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
/**
|
||||
* Show dialog which asks for required conference password.
|
||||
* @returns {Promise<string>} password or nothing if user canceled
|
||||
*/
|
||||
export default function askForPassword () {
|
||||
let titleKey = "dialog.passwordRequired";
|
||||
let passMsg = APP.translation.translateString("dialog.password");
|
||||
let msgString = `
|
||||
<input name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.password"
|
||||
placeholder="${passMsg}" autofocus>
|
||||
`;
|
||||
return new Promise(function (resolve, reject) {
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
msgString,
|
||||
leftButtonKey: "dialog.Ok",
|
||||
submitFunction: $.noop,
|
||||
closeFunction: function (e, v, m, f) {
|
||||
if (v && f.lockKey) {
|
||||
resolve(UIUtil.escapeHtml(f.lockKey));
|
||||
} else {
|
||||
reject(APP.UI.messageHandler.CANCEL);
|
||||
}
|
||||
},
|
||||
focus: ':input:first'
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/* global JitsiMeetJS, APP */
|
||||
|
||||
import InviteDialogView from './InviteDialogView';
|
||||
import createRoomLocker from './RoomLocker';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
/**
|
||||
* Invite module
|
||||
* Constructor takes conference object giving
|
||||
* ability to subscribe on its events
|
||||
*/
|
||||
class Invite {
|
||||
constructor(conference) {
|
||||
this.conference = conference;
|
||||
this.createRoomLocker(conference);
|
||||
this.initDialog();
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registering listeners.
|
||||
* Primarily listeners for conference events.
|
||||
*/
|
||||
registerListeners() {
|
||||
|
||||
this.conference.on(ConferenceEvents.LOCK_STATE_CHANGED,
|
||||
(locked, error) => {
|
||||
|
||||
console.log("Received channel password lock change: ", locked,
|
||||
error);
|
||||
|
||||
if (!locked) {
|
||||
this.roomLocker.resetPassword();
|
||||
}
|
||||
|
||||
this.setLockedFromElsewhere(locked);
|
||||
});
|
||||
|
||||
this.conference.on(ConferenceEvents.USER_ROLE_CHANGED, (id) => {
|
||||
if (APP.conference.isLocalId(id)
|
||||
&& this.isModerator !== this.conference.isModerator) {
|
||||
|
||||
this.setModerator(this.conference.isModerator);
|
||||
}
|
||||
});
|
||||
|
||||
APP.UI.addListener( UIEvents.INVITE_CLICKED,
|
||||
() => { this.openLinkDialog(); });
|
||||
|
||||
APP.UI.addListener( UIEvents.INVITE_URL_INITIALISED,
|
||||
(inviteUrl) => {
|
||||
this.updateInviteUrl(inviteUrl);
|
||||
});
|
||||
|
||||
APP.UI.addListener( UIEvents.PASSWORD_REQUIRED,
|
||||
() => {
|
||||
this.setLockedFromElsewhere(true);
|
||||
this.roomLocker.requirePassword().then(() => {
|
||||
let pass = this.roomLocker.password;
|
||||
// we received that password is required, but user is trying
|
||||
// anyway to login without a password, mark room as not
|
||||
// locked in case he succeeds (maybe someone removed the
|
||||
// password meanwhile), if it is still locked another
|
||||
// password required will be received and the room again
|
||||
// will be marked as locked.
|
||||
if (!pass)
|
||||
this.setLockedFromElsewhere(false);
|
||||
this.conference.join(this.roomLocker.password);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view.
|
||||
* If dialog hasn't been defined -
|
||||
* creates it and updates
|
||||
*/
|
||||
updateView() {
|
||||
if (!this.view) {
|
||||
this.initDialog();
|
||||
}
|
||||
|
||||
this.view.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Room locker factory
|
||||
* @param room
|
||||
* @returns {Object} RoomLocker
|
||||
* @factory
|
||||
*/
|
||||
createRoomLocker(room = this.conference) {
|
||||
let roomLocker = createRoomLocker(room);
|
||||
this.roomLocker = roomLocker;
|
||||
return this.getRoomLocker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Room locker getter
|
||||
* @returns {Object} RoomLocker
|
||||
*/
|
||||
getRoomLocker() {
|
||||
return this.roomLocker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the invite link dialog.
|
||||
*/
|
||||
openLinkDialog () {
|
||||
if (!this.view) {
|
||||
this.initDialog();
|
||||
}
|
||||
|
||||
this.view.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog initialization.
|
||||
* creating view object using as a model this module
|
||||
*/
|
||||
initDialog() {
|
||||
this.password = this.getPassword();
|
||||
this.view = new InviteDialogView(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Password getter
|
||||
* @returns {String} password
|
||||
*/
|
||||
getPassword() {
|
||||
return this.roomLocker.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches between the moderator view and normal view.
|
||||
*
|
||||
* @param isModerator indicates if the participant is moderator
|
||||
*/
|
||||
setModerator(isModerator) {
|
||||
this.isModerator = isModerator;
|
||||
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to unlock the room.
|
||||
* If the current user is moderator.
|
||||
*/
|
||||
setRoomUnlocked() {
|
||||
if (this.isModerator) {
|
||||
this.roomLocker.lock().then(() => {
|
||||
APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK);
|
||||
this.updateView();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to lock the room if
|
||||
* the current user is moderator.
|
||||
* Takes the password.
|
||||
* @param {String} newPass
|
||||
*/
|
||||
setRoomLocked(newPass) {
|
||||
let isModerator = this.isModerator;
|
||||
if (isModerator && (newPass || !this.roomLocker.isLocked)) {
|
||||
this.roomLocker.lock(newPass).then(() => {
|
||||
APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK);
|
||||
this.updateView();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the room invite url.
|
||||
*/
|
||||
updateInviteUrl (newInviteUrl) {
|
||||
this.inviteUrl = newInviteUrl;
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for encoding
|
||||
* Invite URL
|
||||
* @returns {string}
|
||||
*/
|
||||
getEncodedInviteUrl() {
|
||||
return encodeURI(this.inviteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is locked flag.
|
||||
* Delegates to room locker
|
||||
* @returns {Boolean} isLocked
|
||||
*/
|
||||
isLocked() {
|
||||
return this.roomLocker.isLocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flag locked from elsewhere to room locker.
|
||||
* @param isLocked
|
||||
*/
|
||||
setLockedFromElsewhere(isLocked) {
|
||||
let oldLockState = this.roomLocker.lockedElsewhere;
|
||||
if (oldLockState !== isLocked) {
|
||||
this.roomLocker.lockedElsewhere = isLocked;
|
||||
APP.UI.emitEvent(UIEvents.TOGGLE_ROOM_LOCK);
|
||||
this.updateView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Invite;
|
|
@ -0,0 +1,382 @@
|
|||
/* global $, APP, JitsiMeetJS */
|
||||
|
||||
/**
|
||||
* Substate for password
|
||||
* @type {{LOCKED: string, UNLOCKED: string}}
|
||||
*/
|
||||
const States = {
|
||||
LOCKED: 'locked',
|
||||
UNLOCKED: 'unlocked'
|
||||
};
|
||||
|
||||
/**
|
||||
* Class representing view for Invite dialog
|
||||
* @class InviteDialogView
|
||||
*/
|
||||
export default class InviteDialogView {
|
||||
constructor(model) {
|
||||
let InviteAttributesKey = 'inviteUrlDefaultMsg';
|
||||
let title = APP.translation.translateString(InviteAttributesKey);
|
||||
|
||||
this.unlockHint = "unlockHint";
|
||||
this.lockHint = "lockHint";
|
||||
this.model = model;
|
||||
|
||||
if (this.model.inviteUrl === null) {
|
||||
this.inviteAttributes = (
|
||||
`data-i18n="[value]inviteUrlDefaultMsg" value="${title}"`
|
||||
);
|
||||
} else {
|
||||
let encodedInviteUrl = this.model.getEncodedInviteUrl();
|
||||
this.inviteAttributes = `value="${encodedInviteUrl}"`;
|
||||
}
|
||||
|
||||
this.initDialog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of dialog property
|
||||
*/
|
||||
initDialog() {
|
||||
let dialog = {};
|
||||
dialog.closeFunction = this.closeFunction.bind(this);
|
||||
dialog.submitFunction = this.submitFunction.bind(this);
|
||||
dialog.loadedFunction = this.loadedFunction.bind(this);
|
||||
|
||||
let titleKey = "dialog.shareLink";
|
||||
let titleString = APP.translation.generateTranslationHTML(titleKey);
|
||||
|
||||
dialog.titleKey = titleKey;
|
||||
dialog.titleString = titleString;
|
||||
this.dialog = dialog;
|
||||
|
||||
this.dialog.states = this.getStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for submitting dialog
|
||||
* @param e
|
||||
* @param v
|
||||
*/
|
||||
submitFunction(e, v) {
|
||||
if (v && this.model.inviteUrl) {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.button');
|
||||
} else {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.cancel');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for load dialog
|
||||
* @param event
|
||||
*/
|
||||
loadedFunction(event) {
|
||||
if (this.model.inviteUrl) {
|
||||
document.getElementById('inviteLinkRef').select();
|
||||
} else {
|
||||
if (event && event.target) {
|
||||
$(event.target).find('button[value=true]')
|
||||
.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for closing dialog
|
||||
* @param e
|
||||
* @param v
|
||||
* @param m
|
||||
* @param f
|
||||
*/
|
||||
closeFunction(e, v, m, f) {
|
||||
$(document).off('click', '.copyInviteLink', this.copyToClipboard);
|
||||
|
||||
if(!v && !m && !f)
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.close');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all states of the dialog
|
||||
* @returns {{}}
|
||||
*/
|
||||
getStates() {
|
||||
let {
|
||||
titleString
|
||||
} = this.dialog;
|
||||
|
||||
let states = {};
|
||||
|
||||
states[States.UNLOCKED] = {
|
||||
title: titleString,
|
||||
html: this.getShareLinkBlock() + this.getAddPasswordBlock()
|
||||
};
|
||||
states[States.LOCKED] = {
|
||||
title: titleString,
|
||||
html: this.getShareLinkBlock() + this.getPasswordBlock()
|
||||
};
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout for invite link input
|
||||
* @returns {string}
|
||||
*/
|
||||
getShareLinkBlock() {
|
||||
let copyKey = 'dialog.copy';
|
||||
let copyText = APP.translation.translateString(copyKey);
|
||||
let roomLockDescKey = 'roomLocked';
|
||||
let roomLockDesc = APP.translation.translateString(roomLockDescKey);
|
||||
let roomUnlockKey = 'roomUnlocked';
|
||||
let roomUnlock = APP.translation.translateString(roomUnlockKey);
|
||||
let classes = 'button-control button-control_light copyInviteLink';
|
||||
return (
|
||||
`<div class="input-control">
|
||||
<label class="input-control__label" for="inviteLinkRef">
|
||||
${this.dialog.titleString}
|
||||
</label>
|
||||
<div class="input-control__container">
|
||||
<input class="input-control__input inviteLink"
|
||||
id="inviteLinkRef" type="text"
|
||||
${this.inviteAttributes} readonly>
|
||||
<button data-i18n="${copyKey}"
|
||||
class="${classes}">
|
||||
${copyText}
|
||||
</button>
|
||||
</div>
|
||||
<p class="input-control__hint ${this.lockHint}">
|
||||
<span class="icon-security-locked"></span>
|
||||
<span data-i18n="${roomLockDescKey}">${roomLockDesc}</span>
|
||||
</p>
|
||||
<p class="input-control__hint ${this.unlockHint}">
|
||||
<span class="icon-security"></span>
|
||||
<span data-i18n="${roomUnlockKey}">${roomUnlock}</span>
|
||||
</p>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout for adding password input
|
||||
* @returns {string}
|
||||
*/
|
||||
getAddPasswordBlock() {
|
||||
let addPassKey = 'dialog.addPassword';
|
||||
let addPassText = APP.translation.translateString(addPassKey);
|
||||
let addKey = 'dialog.add';
|
||||
let addText = APP.translation.translateString(addKey);
|
||||
let html;
|
||||
|
||||
if (this.model.isModerator) {
|
||||
html = (`
|
||||
<div class="input-control">
|
||||
<label class="input-control__label
|
||||
for="newPasswordInput"
|
||||
data-i18n="${addPassKey}">${addPassText}</label>
|
||||
<div class="input-control__container">
|
||||
<input class="input-control__input" id="newPasswordInput"
|
||||
type="text">
|
||||
<button id="addPasswordBtn" id="inviteDialogAddPassword"
|
||||
disabled data-i18n="${addKey}"
|
||||
class="button-control button-control_light">
|
||||
${addText}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
} else {
|
||||
html = '';
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout for password (when room is locked)
|
||||
* @returns {string}
|
||||
*/
|
||||
getPasswordBlock() {
|
||||
let { password, isModerator } = this.model;
|
||||
let removePassKey = 'dialog.removePassword';
|
||||
let removePassText = APP.translation.translateString(removePassKey);
|
||||
let currentPassKey = 'dialog.currentPassword';
|
||||
let currentPassText = APP.translation.translateString(currentPassKey);
|
||||
let passwordKey = "dialog.passwordLabel";
|
||||
let passwordText = APP.translation.translateString(passwordKey);
|
||||
|
||||
if (isModerator) {
|
||||
return (`
|
||||
<div class="input-control">
|
||||
<label class="input-control__label"
|
||||
data-i18n="${passwordKey}">${passwordText}</label>
|
||||
<div class="input-control__container">
|
||||
<p class="input-control__text"
|
||||
data-i18n="${currentPassKey}">
|
||||
${currentPassText}
|
||||
<span id="inviteDialogPassword"
|
||||
class="input-control__em">
|
||||
${password}
|
||||
</span>
|
||||
</p>
|
||||
<a class="link input-control__right"
|
||||
id="inviteDialogRemovePassword"
|
||||
href="#" data-i18n="${removePassKey}">
|
||||
${removePassText}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
} else {
|
||||
return (`
|
||||
<div class="input-control">
|
||||
<p>A participant protected this call with a password.</p>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Opening the dialog
|
||||
*/
|
||||
open() {
|
||||
let leftButton;
|
||||
let {
|
||||
submitFunction,
|
||||
loadedFunction,
|
||||
closeFunction
|
||||
} = this.dialog;
|
||||
|
||||
let states = this.getStates();
|
||||
|
||||
let buttons = [];
|
||||
let leftButtonKey = "dialog.Invite";
|
||||
let cancelButton
|
||||
= APP.translation.generateTranslationHTML("dialog.Cancel");
|
||||
buttons.push({title: cancelButton, value: false});
|
||||
|
||||
leftButton = APP.translation.generateTranslationHTML(leftButtonKey);
|
||||
buttons.push({ title: leftButton, value: true});
|
||||
|
||||
let initial = this.model.roomLocked ? States.LOCKED : States.UNLOCKED;
|
||||
|
||||
APP.UI.messageHandler.openDialogWithStates(states, {
|
||||
submit: submitFunction,
|
||||
loaded: loadedFunction,
|
||||
close: closeFunction,
|
||||
buttons,
|
||||
size: 'medium'
|
||||
});
|
||||
$.prompt.goToState(initial);
|
||||
|
||||
this.registerListeners();
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting event handlers
|
||||
* used in dialog
|
||||
*/
|
||||
registerListeners() {
|
||||
let $passInput = $('#newPasswordInput');
|
||||
let $addPassBtn = $('#addPasswordBtn');
|
||||
|
||||
$(document).on('click', '.copyInviteLink', this.copyToClipboard);
|
||||
$addPassBtn.on('click', () => {
|
||||
let newPass = $passInput.val();
|
||||
|
||||
if(newPass) {
|
||||
this.model.setRoomLocked(newPass);
|
||||
}
|
||||
});
|
||||
$('#inviteDialogRemovePassword').on('click', () => {
|
||||
this.model.setRoomUnlocked();
|
||||
});
|
||||
$passInput.keyup(this.disableAddPassIfInputEmpty.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking input and if it's empty then
|
||||
* disable add pass button
|
||||
*/
|
||||
disableAddPassIfInputEmpty() {
|
||||
let $passInput = $('#newPasswordInput');
|
||||
let $addPassBtn = $('#addPasswordBtn');
|
||||
|
||||
if(!$passInput.val()) {
|
||||
$addPassBtn.prop('disabled', true);
|
||||
} else {
|
||||
$addPassBtn.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copying text to clipboard
|
||||
*/
|
||||
copyToClipboard() {
|
||||
$('.inviteLink').each(function () {
|
||||
let $el = $(this).closest('.jqistate');
|
||||
|
||||
// TOFIX: We can select only visible elements
|
||||
if($el.css('display') === 'block') {
|
||||
this.select();
|
||||
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
this.blur();
|
||||
}
|
||||
catch (err) {
|
||||
console.error('error when copy the text');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method syncing the view and the model
|
||||
*/
|
||||
updateView() {
|
||||
let pass = this.model.getPassword();
|
||||
if (!pass)
|
||||
pass = APP.translation.translateString("passwordSetRemotely");
|
||||
|
||||
$('#inviteDialogPassword').text(pass);
|
||||
$('#newPasswordInput').val('');
|
||||
this.disableAddPassIfInputEmpty();
|
||||
|
||||
this.updateInviteLink();
|
||||
|
||||
$.prompt.goToState(
|
||||
(this.model.isLocked())
|
||||
? States.LOCKED
|
||||
: States.UNLOCKED);
|
||||
|
||||
let roomLocked = `.${this.lockHint}`;
|
||||
let roomUnlocked = `.${this.unlockHint}`;
|
||||
|
||||
let showDesc = this.model.isLocked() ? roomLocked : roomUnlocked;
|
||||
let hideDesc = !this.model.isLocked() ? roomLocked : roomUnlocked;
|
||||
|
||||
$(showDesc).show();
|
||||
$(hideDesc).hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates invite link
|
||||
*/
|
||||
updateInviteLink() {
|
||||
// If the invite dialog has been already opened we update the
|
||||
// information.
|
||||
let inviteLink = document.querySelectorAll('.inviteLink');
|
||||
let list = Array.from(inviteLink);
|
||||
list.forEach((inviteLink) => {
|
||||
inviteLink.value = this.model.inviteUrl;
|
||||
inviteLink.select();
|
||||
});
|
||||
|
||||
$('#inviteLinkRef').parent()
|
||||
.find('button[value=true]').prop('disabled', false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* global APP, JitsiMeetJS */
|
||||
import askForPassword from './AskForPassword';
|
||||
|
||||
/**
|
||||
* Show notification that user cannot set password for the conference
|
||||
* because server doesn't support that.
|
||||
*/
|
||||
function notifyPasswordNotSupported () {
|
||||
console.warn('room passwords not supported');
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.warning", "dialog.passwordNotSupported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notification that setting password for the conference failed.
|
||||
* @param {Error} err error
|
||||
*/
|
||||
function notifyPasswordFailed(err) {
|
||||
console.warn('setting password failed', err);
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.lockTitle", "dialog.lockMessage");
|
||||
}
|
||||
|
||||
const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||
|
||||
/**
|
||||
* Create new RoomLocker for the conference.
|
||||
* It allows to set or remove password for the conference,
|
||||
* or ask for required password.
|
||||
* @returns {RoomLocker}
|
||||
*/
|
||||
export default function createRoomLocker (room) {
|
||||
let password;
|
||||
|
||||
/**
|
||||
* If the room was locked from someone other than us, we indicate it with
|
||||
* this property in order to have correct roomLocker state of isLocked.
|
||||
* @type {boolean} whether room is locked, but not from us.
|
||||
*/
|
||||
let lockedElsewhere = false;
|
||||
|
||||
/**
|
||||
* @class RoomLocker
|
||||
*/
|
||||
return {
|
||||
get isLocked () {
|
||||
return !!password || lockedElsewhere;
|
||||
},
|
||||
|
||||
get password () {
|
||||
return password;
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows to set new password
|
||||
* @param newPass
|
||||
* @returns {Promise.<TResult>}
|
||||
*/
|
||||
lock (newPass) {
|
||||
return room.lock(newPass).then(() => {
|
||||
password = newPass;
|
||||
// If the password is undefined this means that we're removing
|
||||
// it for everyone.
|
||||
if (!password)
|
||||
lockedElsewhere = false;
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
if (err === ConferenceErrors.PASSWORD_NOT_SUPPORTED) {
|
||||
notifyPasswordNotSupported();
|
||||
} else {
|
||||
notifyPasswordFailed(err);
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets that the room is locked from another user, not us.
|
||||
* @param {boolean} value locked/unlocked state
|
||||
*/
|
||||
set lockedElsewhere (value) {
|
||||
lockedElsewhere = value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether room is locked from someone else.
|
||||
* @returns {boolean} whether room is not locked locally,
|
||||
* but it is still locked.
|
||||
*/
|
||||
get lockedElsewhere () {
|
||||
return lockedElsewhere;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset the password. Can be useful when room
|
||||
* has been unlocked from elsewhere and we can use
|
||||
* this method for sync the pass
|
||||
*/
|
||||
resetPassword() {
|
||||
password = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Asks user for required conference password.
|
||||
*/
|
||||
requirePassword () {
|
||||
return askForPassword().then(
|
||||
newPass => { password = newPass; }
|
||||
).catch(
|
||||
reason => {
|
||||
// user canceled, no pass was entered.
|
||||
// clear, as if we use the same instance several times
|
||||
// pass stays between attempts
|
||||
password = null;
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -55,9 +55,9 @@ function _requestLiveStreamId() {
|
|||
return new Promise(function (resolve, reject) {
|
||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||
state0: {
|
||||
title: msg,
|
||||
html:
|
||||
`<h2>${msg}</h2>
|
||||
<input name="streamId" type="text"
|
||||
`<input name="streamId" type="text"
|
||||
data-i18n="[placeholder]dialog.streamKey"
|
||||
placeholder="${token}" autofocus>`,
|
||||
persistent: false,
|
||||
|
@ -89,7 +89,8 @@ function _requestLiveStreamId() {
|
|||
},
|
||||
|
||||
state1: {
|
||||
html: `<h2>${msg}</h2> ${streamIdRequired}`,
|
||||
title: msg,
|
||||
html: streamIdRequired,
|
||||
persistent: false,
|
||||
buttons: [
|
||||
{title: cancelButton, value: false},
|
||||
|
@ -120,30 +121,30 @@ function _requestLiveStreamId() {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
function _requestRecordingToken () {
|
||||
let msg = APP.translation.generateTranslationHTML("dialog.recordingToken");
|
||||
let titleKey = "dialog.recordingToken";
|
||||
let token = APP.translation.translateString("dialog.token");
|
||||
|
||||
let messageString = (
|
||||
`<input name="recordingToken" type="text"
|
||||
data-i18n="[placeholder]dialog.token"
|
||||
placeholder="${token}" autofocus>`
|
||||
);
|
||||
return new Promise(function (resolve, reject) {
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
`<h2>${msg}</h2>
|
||||
<input name="recordingToken" type="text"
|
||||
data-i18n="[placeholder]dialog.token"
|
||||
placeholder="${token}" autofocus>`,
|
||||
false, "dialog.Save",
|
||||
function (e, v, m, f) {
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
messageString,
|
||||
leftButtonKey: 'dialog.Save',
|
||||
submitFunction: function (e, v, m, f) {
|
||||
if (v && f.recordingToken) {
|
||||
resolve(UIUtil.escapeHtml(f.recordingToken));
|
||||
} else {
|
||||
reject(APP.UI.messageHandler.CANCEL);
|
||||
}
|
||||
},
|
||||
null,
|
||||
function () {
|
||||
closeFunction: function () {
|
||||
dialog = null;
|
||||
},
|
||||
':input:first'
|
||||
);
|
||||
focus: ':input:first'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -170,25 +171,21 @@ function _showStopRecordingPrompt (recordingType) {
|
|||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
||||
title,
|
||||
null,
|
||||
message,
|
||||
null,
|
||||
false,
|
||||
buttonKey,
|
||||
function(e,v) {
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey: title,
|
||||
messageKey: message,
|
||||
leftButtonKey: buttonKey,
|
||||
submitFunction: function(e,v) {
|
||||
if (v) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
null,
|
||||
function () {
|
||||
closeFunction: function () {
|
||||
dialog = null;
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -722,26 +722,25 @@ function getYoutubeLink(url) {
|
|||
*/
|
||||
function showStopVideoPropmpt() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
||||
"dialog.removeSharedVideoTitle",
|
||||
null,
|
||||
"dialog.removeSharedVideoMsg",
|
||||
null,
|
||||
false,
|
||||
"dialog.Remove",
|
||||
function(e,v) {
|
||||
if (v) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
null,
|
||||
function () {
|
||||
dialog = null;
|
||||
let submitFunction = function(e,v) {
|
||||
if (v) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let closeFunction = function () {
|
||||
dialog = null;
|
||||
};
|
||||
|
||||
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey: "dialog.removeSharedVideoTitle",
|
||||
msgKey: "dialog.removeSharedVideoMsg",
|
||||
leftButtonKey: "dialog.Remove",
|
||||
submitFunction,
|
||||
closeFunction
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -763,8 +762,8 @@ function requestVideoLink() {
|
|||
return new Promise(function (resolve, reject) {
|
||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||
state0: {
|
||||
title: title,
|
||||
html: `
|
||||
<h2>${title}</h2>
|
||||
<input name="sharedVideoUrl" type="text"
|
||||
data-i18n="[placeholder]defaultLink"
|
||||
data-i18n-options="${JSON.stringify(i18nOptions)}"
|
||||
|
@ -803,7 +802,8 @@ function requestVideoLink() {
|
|||
},
|
||||
|
||||
state1: {
|
||||
html: `<h2>${title}</h2> ${linkError}`,
|
||||
title: title,
|
||||
html: linkError,
|
||||
persistent: false,
|
||||
buttons: [
|
||||
{title: cancelButton, value: false},
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Class representing Contact model
|
||||
* @class Contact
|
||||
*/
|
||||
export default class Contact {
|
||||
constructor(opts) {
|
||||
let {
|
||||
id,
|
||||
avatar,
|
||||
name,
|
||||
isLocal
|
||||
} = opts;
|
||||
|
||||
this.id = id;
|
||||
this.avatar = avatar || '';
|
||||
this.name = name || '';
|
||||
this.isLocal = isLocal || false;
|
||||
}
|
||||
}
|
|
@ -1,151 +1,94 @@
|
|||
/* global $, APP, interfaceConfig */
|
||||
import Avatar from '../../avatar/Avatar';
|
||||
/* global APP */
|
||||
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import UIUtil from '../../util/UIUtil';
|
||||
|
||||
let numberOfContacts = 0;
|
||||
import ContactListView from './ContactListView';
|
||||
import Contact from './Contact';
|
||||
|
||||
/**
|
||||
* Updates the number of participants in the contact list button and sets
|
||||
* the glow
|
||||
* @param delta indicates whether a new user has joined (1) or someone has
|
||||
* left(-1)
|
||||
* Model for the Contact list.
|
||||
*
|
||||
* @class ContactList
|
||||
*/
|
||||
function updateNumberOfParticipants(delta) {
|
||||
numberOfContacts += delta;
|
||||
|
||||
if (numberOfContacts <= 0) {
|
||||
console.error("Invalid number of participants: " + numberOfContacts);
|
||||
return;
|
||||
class ContactList {
|
||||
constructor(conference) {
|
||||
this.conference = conference;
|
||||
this.contacts = [];
|
||||
this.roomLocked = false;
|
||||
ContactListView.init(this);
|
||||
}
|
||||
|
||||
$("#numberOfParticipants").text(numberOfContacts);
|
||||
|
||||
$("#contacts_container>div.title").text(
|
||||
APP.translation.translateString("contactlist")
|
||||
+ ' (' + numberOfContacts + ')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the avatar element.
|
||||
*
|
||||
* @return {object} the newly created avatar element
|
||||
*/
|
||||
function createAvatar(jid) {
|
||||
let avatar = document.createElement('img');
|
||||
avatar.className = "icon-avatar avatar";
|
||||
avatar.src = Avatar.getAvatarUrl(jid);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the display name paragraph.
|
||||
*
|
||||
* @param displayName the display name to set
|
||||
*/
|
||||
function createDisplayNameParagraph(key, displayName) {
|
||||
let p = document.createElement('p');
|
||||
if (displayName) {
|
||||
p.innerHTML = displayName;
|
||||
} else if(key) {
|
||||
p.setAttribute("data-i18n",key);
|
||||
p.innerHTML = APP.translation.translateString(key);
|
||||
/**
|
||||
* Is locked flag.
|
||||
* Delegates to Invite module
|
||||
* TO FIX: find a better way to access the IS LOCKED state of the invite.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isLocked() {
|
||||
return APP.conference.invite.isLocked();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
function getContactEl (id) {
|
||||
return $(`#contacts>li[id="${id}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact list.
|
||||
*/
|
||||
var ContactList = {
|
||||
init (emitter) {
|
||||
this.emitter = emitter;
|
||||
},
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
* Adding new participant.
|
||||
*
|
||||
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
|
||||
* otherwise
|
||||
* @param id
|
||||
* @param isLocal
|
||||
*/
|
||||
isVisible () {
|
||||
return UIUtil.isVisible(document.getElementById("contactlist"));
|
||||
},
|
||||
addContact(id, isLocal) {
|
||||
let isExist = this.contacts.some((el) => el.id === id);
|
||||
|
||||
/**
|
||||
* Adds a contact for the given id.
|
||||
* @param isLocal is an id for the local user.
|
||||
*/
|
||||
addContact (id, isLocal) {
|
||||
let contactlist = $('#contacts');
|
||||
|
||||
let newContact = document.createElement('li');
|
||||
newContact.id = id;
|
||||
newContact.className = "clickable";
|
||||
newContact.onclick = (event) => {
|
||||
if (event.currentTarget.className === "clickable") {
|
||||
this.emitter.emit(UIEvents.CONTACT_CLICKED, id);
|
||||
}
|
||||
};
|
||||
|
||||
if (interfaceConfig.SHOW_CONTACTLIST_AVATARS)
|
||||
newContact.appendChild(createAvatar(id));
|
||||
|
||||
newContact.appendChild(
|
||||
createDisplayNameParagraph(
|
||||
isLocal ? interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME : null,
|
||||
isLocal ? null : interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME));
|
||||
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
contactlist.prepend(newContact);
|
||||
} else {
|
||||
contactlist.append(newContact);
|
||||
if (!isExist) {
|
||||
let newContact = new Contact({ id, isLocal });
|
||||
this.contacts.push(newContact);
|
||||
APP.UI.emitEvent(UIEvents.CONTACT_ADDED, { id, isLocal });
|
||||
}
|
||||
updateNumberOfParticipants(1);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a contact for the given id.
|
||||
* Removing participant.
|
||||
*
|
||||
* @param id
|
||||
* @returns {Array|*}
|
||||
*/
|
||||
removeContact (id) {
|
||||
let contact = getContactEl(id);
|
||||
removeContact(id) {
|
||||
this.contacts = this.contacts.filter((el) => el.id !== id);
|
||||
APP.UI.emitEvent(UIEvents.CONTACT_REMOVED, { id });
|
||||
return this.contacts;
|
||||
}
|
||||
|
||||
if (contact.length > 0) {
|
||||
contact.remove();
|
||||
updateNumberOfParticipants(-1);
|
||||
}
|
||||
},
|
||||
|
||||
setClickable (id, isClickable) {
|
||||
getContactEl(id).toggleClass('clickable', isClickable);
|
||||
},
|
||||
|
||||
onDisplayNameChange (id, displayName) {
|
||||
if(!displayName)
|
||||
/**
|
||||
* Changing the display name.
|
||||
*
|
||||
* @param id
|
||||
* @param name
|
||||
*/
|
||||
onDisplayNameChange (id, name) {
|
||||
if(!name)
|
||||
return;
|
||||
if (id === 'localVideoContainer') {
|
||||
id = APP.conference.getMyUserId();
|
||||
}
|
||||
let contactName = $(`#contacts #${id}>p`);
|
||||
|
||||
if (contactName.text() !== displayName) {
|
||||
contactName.text(displayName);
|
||||
}
|
||||
},
|
||||
|
||||
changeUserAvatar (id, avatarUrl) {
|
||||
// set the avatar in the contact list
|
||||
let contact = $(`#${id}>img`);
|
||||
if (contact.length > 0) {
|
||||
contact.attr('src', avatarUrl);
|
||||
}
|
||||
let contacts = this.contacts.filter((el) => el.id === id);
|
||||
contacts.forEach((el) => {
|
||||
el.name = name;
|
||||
});
|
||||
APP.UI.emitEvent(UIEvents.DISPLAY_NAME_CHANGED, { id, name });
|
||||
}
|
||||
};
|
||||
|
||||
export default ContactList;
|
||||
/**
|
||||
* Changing the avatar.
|
||||
*
|
||||
* @param id
|
||||
* @param avatar
|
||||
*/
|
||||
changeUserAvatar (id, avatar) {
|
||||
let contacts = this.contacts.filter((el) => el.id === id);
|
||||
contacts.forEach((el) => {
|
||||
el.avatar = avatar;
|
||||
});
|
||||
APP.UI.emitEvent(UIEvents.USER_AVATAR_CHANGED, { id, avatar });
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactList;
|
|
@ -0,0 +1,261 @@
|
|||
/* global $, APP, interfaceConfig */
|
||||
import Avatar from '../../avatar/Avatar';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import UIUtil from '../../util/UIUtil';
|
||||
|
||||
let numberOfContacts = 0;
|
||||
|
||||
/**
|
||||
* Updates the number of participants in the contact list button and sets
|
||||
* the glow
|
||||
* @param delta indicates whether a new user has joined (1) or someone has
|
||||
* left(-1)
|
||||
*/
|
||||
function updateNumberOfParticipants(delta) {
|
||||
numberOfContacts += delta;
|
||||
|
||||
if (numberOfContacts <= 0) {
|
||||
console.error("Invalid number of participants: " + numberOfContacts);
|
||||
return;
|
||||
}
|
||||
|
||||
$("#numberOfParticipants").text(numberOfContacts);
|
||||
|
||||
$("#contacts_container>div.title").text(
|
||||
APP.translation.translateString("contactlist")
|
||||
+ ' (' + numberOfContacts + ')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the avatar element.
|
||||
*
|
||||
* @return {object} the newly created avatar element
|
||||
*/
|
||||
function createAvatar(jid) {
|
||||
let avatar = document.createElement('img');
|
||||
avatar.className = "icon-avatar avatar";
|
||||
avatar.src = Avatar.getAvatarUrl(jid);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the display name paragraph.
|
||||
*
|
||||
* @param displayName the display name to set
|
||||
*/
|
||||
function createDisplayNameParagraph(key, displayName) {
|
||||
let p = document.createElement('p');
|
||||
if (displayName) {
|
||||
p.innerHTML = displayName;
|
||||
} else if(key) {
|
||||
p.setAttribute("data-i18n",key);
|
||||
p.innerHTML = APP.translation.translateString(key);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for current contact element
|
||||
* @param id
|
||||
* @returns {JQuery}
|
||||
*/
|
||||
function getContactEl (id) {
|
||||
return $(`#contacts>li[id="${id}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact list.
|
||||
*/
|
||||
var ContactListView = {
|
||||
init (model) {
|
||||
this.model = model;
|
||||
this.lockKey = 'roomLocked';
|
||||
this.unlockKey = 'roomUnlocked';
|
||||
this.addInviteButton();
|
||||
this.registerListeners();
|
||||
this.toggleLock();
|
||||
},
|
||||
/**
|
||||
* Adds layout for invite button
|
||||
*/
|
||||
addInviteButton() {
|
||||
let container = document.getElementById('contacts_container');
|
||||
let title = container.firstElementChild;
|
||||
|
||||
let htmlLayout = this.getInviteButtonLayout();
|
||||
title.insertAdjacentHTML('afterend', htmlLayout);
|
||||
$(document).on('click', '#addParticipantsBtn', () => {
|
||||
APP.UI.emitEvent(UIEvents.INVITE_CLICKED);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Returns layout for invite button
|
||||
*/
|
||||
getInviteButtonLayout() {
|
||||
let classes = 'button-control button-control_primary';
|
||||
classes += ' button-control_full-width';
|
||||
let key = 'addParticipants';
|
||||
let text = APP.translation.translateString(key);
|
||||
|
||||
let lockedHtml = this.getLockDescriptionLayout(this.lockKey);
|
||||
let unlockedHtml = this.getLockDescriptionLayout(this.unlockKey);
|
||||
|
||||
let html = (
|
||||
`<div class="sideToolbarBlock first">
|
||||
<button id="addParticipantsBtn"
|
||||
data-i18n="${key}"
|
||||
class="${classes}">
|
||||
${text}
|
||||
</button>
|
||||
<div>
|
||||
${lockedHtml}
|
||||
${unlockedHtml}
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
return html;
|
||||
},
|
||||
/**
|
||||
* Adds layout for lock description
|
||||
*/
|
||||
getLockDescriptionLayout(key) {
|
||||
let classes = "input-control__hint input-control_full-width";
|
||||
let description = APP.translation.translateString(key);
|
||||
let padlockSuffix = '';
|
||||
if (key === this.lockKey) {
|
||||
padlockSuffix = '-locked';
|
||||
}
|
||||
|
||||
return `<p id="contactList${key}" class="${classes}">
|
||||
<span class="icon-security${padlockSuffix}"></span>
|
||||
<span data-i18n="${key}">${description}</span>
|
||||
</p>`;
|
||||
},
|
||||
/**
|
||||
* Setup listeners
|
||||
*/
|
||||
registerListeners() {
|
||||
let removeContact = this.onRemoveContact.bind(this);
|
||||
let changeAvatar = this.changeUserAvatar.bind(this);
|
||||
let displayNameChange = this.onDisplayNameChange.bind(this);
|
||||
|
||||
APP.UI.addListener( UIEvents.TOGGLE_ROOM_LOCK,
|
||||
this.toggleLock.bind(this));
|
||||
APP.UI.addListener( UIEvents.CONTACT_ADDED,
|
||||
this.onAddContact.bind(this));
|
||||
|
||||
APP.UI.addListener(UIEvents.CONTACT_REMOVED, removeContact);
|
||||
APP.UI.addListener(UIEvents.USER_AVATAR_CHANGED, changeAvatar);
|
||||
APP.UI.addListener(UIEvents.DISPLAY_NAME_CHANGED, displayNameChange);
|
||||
},
|
||||
/**
|
||||
* Updating the view according the model
|
||||
* @param type {String} type of change
|
||||
* @returns {Promise}
|
||||
*/
|
||||
toggleLock() {
|
||||
let isLocked = this.model.isLocked();
|
||||
let showKey = isLocked ? this.lockKey : this.unlockKey;
|
||||
let hideKey = !isLocked ? this.lockKey : this.unlockKey;
|
||||
let showId = `contactList${showKey}`;
|
||||
let hideId = `contactList${hideKey}`;
|
||||
|
||||
$(`#${showId}`).show();
|
||||
$(`#${hideId}`).hide();
|
||||
},
|
||||
/**
|
||||
* Indicates if the chat is currently visible.
|
||||
*
|
||||
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
|
||||
* otherwise
|
||||
*/
|
||||
isVisible () {
|
||||
return UIUtil.isVisible(document.getElementById("contactlist"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for Adding a contact for the given id.
|
||||
* @param isLocal is an id for the local user.
|
||||
*/
|
||||
onAddContact (data) {
|
||||
let { id, isLocal } = data;
|
||||
let contactlist = $('#contacts');
|
||||
let newContact = document.createElement('li');
|
||||
newContact.id = id;
|
||||
newContact.className = "clickable";
|
||||
newContact.onclick = (event) => {
|
||||
if (event.currentTarget.className === "clickable") {
|
||||
APP.UI.emitEvent(UIEvents.CONTACT_CLICKED, id);
|
||||
}
|
||||
};
|
||||
|
||||
if (interfaceConfig.SHOW_CONTACTLIST_AVATARS)
|
||||
newContact.appendChild(createAvatar(id));
|
||||
|
||||
newContact.appendChild(
|
||||
createDisplayNameParagraph(
|
||||
isLocal ? interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME : null,
|
||||
isLocal ? null : interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME));
|
||||
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
contactlist.prepend(newContact);
|
||||
} else {
|
||||
contactlist.append(newContact);
|
||||
}
|
||||
updateNumberOfParticipants(1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for removing
|
||||
* a contact for the given id.
|
||||
*/
|
||||
onRemoveContact (data) {
|
||||
let { id } = data;
|
||||
let contact = getContactEl(id);
|
||||
|
||||
if (contact.length > 0) {
|
||||
contact.remove();
|
||||
updateNumberOfParticipants(-1);
|
||||
}
|
||||
},
|
||||
|
||||
setClickable (id, isClickable) {
|
||||
getContactEl(id).toggleClass('clickable', isClickable);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes display name of the user
|
||||
* defined by its id
|
||||
* @param data
|
||||
*/
|
||||
onDisplayNameChange (data) {
|
||||
let { id, name } = data;
|
||||
if(!name)
|
||||
return;
|
||||
if (id === 'localVideoContainer') {
|
||||
id = APP.conference.getMyUserId();
|
||||
}
|
||||
let contactName = $(`#contacts #${id}>p`);
|
||||
|
||||
if (contactName.text() !== name) {
|
||||
contactName.text(name);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes user avatar
|
||||
* @param data
|
||||
*/
|
||||
changeUserAvatar (data) {
|
||||
let { id, avatar } = data;
|
||||
// set the avatar in the contact list
|
||||
let contact = $(`#${id}>img`);
|
||||
if (contact.length > 0) {
|
||||
contact.attr('src', avatar);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default ContactListView;
|
|
@ -3,64 +3,8 @@ import UIUtil from '../util/UIUtil';
|
|||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import SideContainerToggler from "../side_pannels/SideContainerToggler";
|
||||
|
||||
let roomUrl = null;
|
||||
let emitter = null;
|
||||
|
||||
/**
|
||||
* Opens the invite link dialog.
|
||||
*/
|
||||
function openLinkDialog () {
|
||||
let inviteAttributes;
|
||||
|
||||
if (roomUrl === null) {
|
||||
inviteAttributes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
|
||||
APP.translation.translateString("roomUrlDefaultMsg") + '"';
|
||||
} else {
|
||||
inviteAttributes = "value=\"" + encodeURI(roomUrl) + "\"";
|
||||
}
|
||||
|
||||
let inviteLinkId = "inviteLinkRef";
|
||||
let focusInviteLink = function() {
|
||||
$('#' + inviteLinkId).focus();
|
||||
$('#' + inviteLinkId).select();
|
||||
};
|
||||
|
||||
let title = APP.translation.generateTranslationHTML("dialog.shareLink");
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, title, null,
|
||||
'<input id="' + inviteLinkId + '" type="text" '
|
||||
+ inviteAttributes + ' readonly/>',
|
||||
false, "dialog.copy",
|
||||
function (e, v) {
|
||||
if (v && roomUrl) {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.button');
|
||||
|
||||
focusInviteLink();
|
||||
|
||||
document.execCommand('copy');
|
||||
}
|
||||
else {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.cancel');
|
||||
}
|
||||
},
|
||||
function (event) {
|
||||
if (!roomUrl) {
|
||||
if (event && event.target) {
|
||||
$(event.target).find('button[value=true]')
|
||||
.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
focusInviteLink();
|
||||
}
|
||||
},
|
||||
function (e, v, m, f) {
|
||||
if(!v && !m && !f)
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.close');
|
||||
},
|
||||
'Copy' // Focus Copy button.
|
||||
);
|
||||
}
|
||||
let Toolbar;
|
||||
|
||||
const buttonHandlers = {
|
||||
"toolbar_button_profile": function () {
|
||||
|
@ -98,13 +42,9 @@ const buttonHandlers = {
|
|||
emitter.emit(UIEvents.VIDEO_MUTED, true);
|
||||
}
|
||||
},
|
||||
"toolbar_button_security": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.lock.clicked');
|
||||
emitter.emit(UIEvents.ROOM_LOCK_CLICKED);
|
||||
},
|
||||
"toolbar_button_link": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.clicked');
|
||||
openLinkDialog();
|
||||
emitter.emit(UIEvents.INVITE_CLICKED);
|
||||
},
|
||||
"toolbar_button_chat": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.chat.toggled');
|
||||
|
@ -158,21 +98,20 @@ const buttonHandlers = {
|
|||
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||
},
|
||||
"toolbar_button_logout": function () {
|
||||
let titleKey = "dialog.logoutTitle";
|
||||
let msgKey = "dialog.logoutQuestion";
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.logout.clicked');
|
||||
// Ask for confirmation
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
"dialog.logoutTitle",
|
||||
null,
|
||||
"dialog.logoutQuestion",
|
||||
null,
|
||||
false,
|
||||
"dialog.Yes",
|
||||
function (evt, yes) {
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
msgKey,
|
||||
leftButtonKey: "dialog.Yes",
|
||||
submitFunction: function (evt, yes) {
|
||||
if (yes) {
|
||||
emitter.emit(UIEvents.LOGOUT);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
"toolbar_film_strip": function () {
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
|
@ -246,10 +185,6 @@ const defaultToolbarButtons = {
|
|||
content: 'Share screen',
|
||||
i18n: '[content]toolbar.sharescreen'
|
||||
},
|
||||
'security': {
|
||||
id: 'toolbar_button_security',
|
||||
tooltipKey: 'toolbar.lock'
|
||||
},
|
||||
'invite': {
|
||||
id: 'toolbar_button_link',
|
||||
tooltipKey: 'toolbar.invite',
|
||||
|
@ -344,27 +279,28 @@ function showSipNumberInput () {
|
|||
let defaultNumber = config.defaultSipNumber
|
||||
? config.defaultSipNumber
|
||||
: '';
|
||||
|
||||
let titleKey = "dialog.sipMsg";
|
||||
let sipMsg = APP.translation.generateTranslationHTML("dialog.sipMsg");
|
||||
APP.UI.messageHandler.openTwoButtonDialog(
|
||||
null, null, null,
|
||||
`<h2>${sipMsg}</h2>
|
||||
<input
|
||||
name="sipNumber"
|
||||
type="text"
|
||||
value="${defaultNumber}"
|
||||
autofocus>`,
|
||||
false, "dialog.Dial",
|
||||
function (e, v, m, f) {
|
||||
let msgString = (`
|
||||
<input name="sipNumber" type="text"
|
||||
value="${defaultNumber}" autofocus>
|
||||
`);
|
||||
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
titleString: sipMsg,
|
||||
msgString,
|
||||
leftButtonKey: "dialog.Dial",
|
||||
submitFunction: function (e, v, m, f) {
|
||||
if (v && f.sipNumber) {
|
||||
emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
|
||||
}
|
||||
},
|
||||
null, null, ':input:first'
|
||||
);
|
||||
focus: ':input:first'
|
||||
});
|
||||
}
|
||||
|
||||
const Toolbar = {
|
||||
Toolbar = {
|
||||
init (eventEmitter) {
|
||||
emitter = eventEmitter;
|
||||
// The toolbar is enabled by default.
|
||||
|
@ -446,41 +382,6 @@ const Toolbar = {
|
|||
isEnabled() {
|
||||
return this.enabled;
|
||||
},
|
||||
/**
|
||||
* Updates the room invite url.
|
||||
*/
|
||||
updateRoomUrl (newRoomUrl) {
|
||||
roomUrl = newRoomUrl;
|
||||
|
||||
// If the invite dialog has been already opened we update the
|
||||
// information.
|
||||
let inviteLink = document.getElementById('inviteLinkRef');
|
||||
if (inviteLink) {
|
||||
inviteLink.value = roomUrl;
|
||||
inviteLink.select();
|
||||
$('#inviteLinkRef').parent()
|
||||
.find('button[value=true]').prop('disabled', false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unlocks the lock button state.
|
||||
*/
|
||||
unlockLockButton () {
|
||||
if ($("#toolbar_button_security").hasClass("icon-security-locked"))
|
||||
UIUtil.buttonClick("toolbar_button_security",
|
||||
"icon-security icon-security-locked");
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the lock button state to locked.
|
||||
*/
|
||||
lockLockButton () {
|
||||
if ($("#toolbar_button_security").hasClass("icon-security"))
|
||||
UIUtil.buttonClick("toolbar_button_security",
|
||||
"icon-security icon-security-locked");
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows or hides authentication button
|
||||
* @param show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
|
|
|
@ -52,8 +52,10 @@ var messageHandler = {
|
|||
}
|
||||
|
||||
return $.prompt(message, {
|
||||
title: title,
|
||||
title: this._getFormattedTitleString(title),
|
||||
persistent: false,
|
||||
promptspeed: 0,
|
||||
classes: this._getDialogClasses(),
|
||||
close: function (e, v, m, f) {
|
||||
if(closeFunction)
|
||||
closeFunction(e, v, m, f);
|
||||
|
@ -79,16 +81,31 @@ var messageHandler = {
|
|||
* the user press 'enter'. Indexed from 0.
|
||||
* @return the prompt that was created, or null
|
||||
*/
|
||||
openTwoButtonDialog: function(titleKey, titleString, msgKey, msgString,
|
||||
persistent, leftButtonKey, submitFunction, loadedFunction,
|
||||
closeFunction, focus, defaultButton) {
|
||||
openTwoButtonDialog: function(options) {
|
||||
let {
|
||||
titleKey,
|
||||
titleString,
|
||||
msgKey,
|
||||
msgString,
|
||||
leftButtonKey,
|
||||
submitFunction,
|
||||
loadedFunction,
|
||||
closeFunction,
|
||||
focus,
|
||||
size,
|
||||
defaultButton,
|
||||
wrapperClass,
|
||||
classes
|
||||
} = options;
|
||||
|
||||
if (!popupEnabled || twoButtonDialog)
|
||||
return null;
|
||||
|
||||
var buttons = [];
|
||||
|
||||
var leftButton = APP.translation.generateTranslationHTML(leftButtonKey);
|
||||
var leftButton = leftButtonKey ?
|
||||
APP.translation.generateTranslationHTML(leftButtonKey) :
|
||||
APP.translation.generateTranslationHTML('dialog.Submit');
|
||||
buttons.push({ title: leftButton, value: true});
|
||||
|
||||
var cancelButton
|
||||
|
@ -102,22 +119,32 @@ var messageHandler = {
|
|||
if (msgKey) {
|
||||
message = APP.translation.generateTranslationHTML(msgKey);
|
||||
}
|
||||
classes = classes || this._getDialogClasses(size);
|
||||
if (wrapperClass) {
|
||||
classes.prompt += ` ${wrapperClass}`;
|
||||
}
|
||||
|
||||
twoButtonDialog = $.prompt(message, {
|
||||
title: title,
|
||||
title: this._getFormattedTitleString(title),
|
||||
persistent: false,
|
||||
buttons: buttons,
|
||||
defaultButton: defaultButton,
|
||||
focus: focus,
|
||||
loaded: loadedFunction,
|
||||
promptspeed: 0,
|
||||
classes,
|
||||
submit: function (e, v, m, f) {
|
||||
twoButtonDialog = null;
|
||||
if (submitFunction)
|
||||
submitFunction(e, v, m, f);
|
||||
if (v){
|
||||
if (submitFunction)
|
||||
submitFunction(e, v, m, f);
|
||||
}
|
||||
},
|
||||
close: function (e, v, m, f) {
|
||||
twoButtonDialog = null;
|
||||
if (closeFunction)
|
||||
if (closeFunction) {
|
||||
closeFunction(e, v, m, f);
|
||||
}
|
||||
}
|
||||
});
|
||||
return twoButtonDialog;
|
||||
|
@ -144,14 +171,16 @@ var messageHandler = {
|
|||
if (!popupEnabled)
|
||||
return;
|
||||
|
||||
var args = {
|
||||
title: titleString,
|
||||
let args = {
|
||||
title: this._getFormattedTitleString(titleString),
|
||||
persistent: persistent,
|
||||
buttons: buttons,
|
||||
defaultButton: 1,
|
||||
promptspeed: 0,
|
||||
loaded: loadedFunction,
|
||||
submit: submitFunction,
|
||||
close: closeFunction
|
||||
close: closeFunction,
|
||||
classes: this._getDialogClasses()
|
||||
};
|
||||
|
||||
if (persistent) {
|
||||
|
@ -161,6 +190,40 @@ var messageHandler = {
|
|||
return new Impromptu(msgString, args);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the formatted title string.
|
||||
*
|
||||
* @return the title string formatted as a div.
|
||||
*/
|
||||
_getFormattedTitleString(titleString) {
|
||||
let $titleString = $('<h2>');
|
||||
$titleString.addClass('aui-dialog2-header-main');
|
||||
$titleString.append(titleString);
|
||||
titleString = $('<div>').append($titleString).html();
|
||||
|
||||
return titleString;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the dialog css classes.
|
||||
*
|
||||
* @return the dialog css classes
|
||||
*/
|
||||
_getDialogClasses(size = 'small') {
|
||||
return {
|
||||
box: '',
|
||||
form: '',
|
||||
prompt: `dialog aui-layer aui-dialog2 aui-dialog2-${size}`,
|
||||
close: 'aui-icon aui-icon-small aui-iconfont-close-dialog',
|
||||
fade: 'aui-blanket',
|
||||
button: 'button-control',
|
||||
message: 'aui-dialog2-content',
|
||||
buttons: 'aui-dialog2-footer',
|
||||
defaultButton: 'button-control_primary',
|
||||
title: 'aui-dialog2-header'
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes currently opened dialog.
|
||||
*/
|
||||
|
@ -176,7 +239,18 @@ var messageHandler = {
|
|||
openDialogWithStates: function (statesObject, options) {
|
||||
if (!popupEnabled)
|
||||
return;
|
||||
let { classes, size } = options;
|
||||
let defaultClasses = this._getDialogClasses(size);
|
||||
options.classes = Object.assign({}, defaultClasses, classes);
|
||||
options.promptspeed = options.promptspeed || 0;
|
||||
|
||||
for (let state in statesObject) {
|
||||
let currentState = statesObject[state];
|
||||
if(currentState.title) {
|
||||
let title = currentState.title;
|
||||
currentState.title = this._getFormattedTitleString(title);
|
||||
}
|
||||
}
|
||||
return new Impromptu(statesObject, options);
|
||||
},
|
||||
|
||||
|
@ -210,6 +284,7 @@ var messageHandler = {
|
|||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
return popup;
|
||||
},
|
||||
|
||||
|
|
|
@ -508,6 +508,11 @@ SmallVideo.prototype.avatarChanged = function (avatarUrl) {
|
|||
* @param show whether to show or hide.
|
||||
*/
|
||||
SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
||||
// Don't create and show dominant speaker indicator if
|
||||
// DISABLE_DOMINANT_SPEAKER_INDICATOR is true
|
||||
if (interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR)
|
||||
return;
|
||||
|
||||
if (!this.container) {
|
||||
console.warn( "Unable to set dominant speaker indicator - "
|
||||
+ this.videoSpanId + " does not exist");
|
||||
|
|
|
@ -172,19 +172,23 @@ var KeyboardShortcut = {
|
|||
*/
|
||||
_addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
|
||||
|
||||
var listElement = document.createElement("li");
|
||||
let listElement = document.createElement("li");
|
||||
let itemClass = 'shortcuts-list__item';
|
||||
listElement.className = itemClass;
|
||||
listElement.id = shortcutChar;
|
||||
|
||||
var spanElement = document.createElement("span");
|
||||
let spanElement = document.createElement("span");
|
||||
spanElement.className = "item-action";
|
||||
|
||||
var kbdElement = document.createElement("kbd");
|
||||
kbdElement.className = "regular-key";
|
||||
let kbdElement = document.createElement("kbd");
|
||||
let classes = 'aui-label regular-key';
|
||||
kbdElement.className = classes;
|
||||
kbdElement.innerHTML = shortcutChar;
|
||||
spanElement.appendChild(kbdElement);
|
||||
|
||||
var descriptionElement = document.createElement("span");
|
||||
descriptionElement.className = "item-description";
|
||||
let descriptionElement = document.createElement("span");
|
||||
let descriptionClass = "shortcuts-list__description";
|
||||
descriptionElement.className = descriptionClass;
|
||||
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
|
||||
descriptionElement.innerHTML
|
||||
= APP.translation.translateString(shortcutDescriptionKey);
|
||||
|
@ -192,7 +196,7 @@ var KeyboardShortcut = {
|
|||
listElement.appendChild(spanElement);
|
||||
listElement.appendChild(descriptionElement);
|
||||
|
||||
var parentListElement
|
||||
let parentListElement
|
||||
= document.getElementById("keyboard-shortcuts-list");
|
||||
|
||||
if (parentListElement)
|
||||
|
|
|
@ -22,13 +22,16 @@ export default {
|
|||
VIDEO_MUTED: "UI.video_muted",
|
||||
ETHERPAD_CLICKED: "UI.etherpad_clicked",
|
||||
SHARED_VIDEO_CLICKED: "UI.start_shared_video",
|
||||
/**
|
||||
* Indicates that an invite button has been clicked.
|
||||
*/
|
||||
INVITE_CLICKED: "UI.invite_clicked",
|
||||
/**
|
||||
* Updates shared video with params: url, state, time(optional)
|
||||
* Where url is the video link, state is stop/start/pause and time is the
|
||||
* current video playing time.
|
||||
*/
|
||||
UPDATE_SHARED_VIDEO: "UI.update_shared_video",
|
||||
ROOM_LOCK_CLICKED: "UI.room_lock_clicked",
|
||||
USER_KICKED: "UI.user_kicked",
|
||||
REMOTE_AUDIO_MUTED: "UI.remote_audio_muted",
|
||||
FULLSCREEN_TOGGLE: "UI.fullscreen_toggle",
|
||||
|
@ -114,5 +117,40 @@ export default {
|
|||
/**
|
||||
* Notifies that the avatar is displayed or not on the largeVideo.
|
||||
*/
|
||||
LARGE_VIDEO_AVATAR_DISPLAYED: "UI.large_video_avatar_displayed"
|
||||
LARGE_VIDEO_AVATAR_DISPLAYED: "UI.large_video_avatar_displayed",
|
||||
|
||||
/**
|
||||
* Toggling room lock
|
||||
*/
|
||||
TOGGLE_ROOM_LOCK: "UI.toggle_room_lock",
|
||||
|
||||
/**
|
||||
* Adding contact to contact list
|
||||
*/
|
||||
CONTACT_ADDED: "UI.contact_added",
|
||||
|
||||
/**
|
||||
* Removing the contact from contact list
|
||||
*/
|
||||
CONTACT_REMOVED: "UI.contact_removed",
|
||||
|
||||
/**
|
||||
* Indicates that a user avatar has changed.
|
||||
*/
|
||||
USER_AVATAR_CHANGED: "UI.user_avatar_changed",
|
||||
|
||||
/**
|
||||
* Display name changed.
|
||||
*/
|
||||
DISPLAY_NAME_CHANGED: "UI.display_name_changed",
|
||||
|
||||
/**
|
||||
* Indicates that the invite url has been initialised.
|
||||
*/
|
||||
INVITE_URL_INITIALISED: "UI.invite_url_initialised",
|
||||
|
||||
/**
|
||||
* Indicates that a password is required for the call.
|
||||
*/
|
||||
PASSWORD_REQUIRED: "UI.password_required"
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue