Dialogs re-design, invite and password modifications
This commit is contained in:
parent
d5541f612f
commit
74f31db434
|
@ -1,8 +1,8 @@
|
||||||
/* global $, APP, JitsiMeetJS, config, interfaceConfig */
|
/* global $, APP, JitsiMeetJS, config, interfaceConfig */
|
||||||
import {openConnection} from './connection';
|
import {openConnection} from './connection';
|
||||||
//FIXME:
|
import Invite from './modules/UI/invite/Invite';
|
||||||
import createRoomLocker from './modules/UI/authentication/RoomLocker';
|
import ContactList from './modules/UI/side_pannels/contactlist/ContactList';
|
||||||
//FIXME:
|
|
||||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||||
|
|
||||||
import ConnectionQuality from './modules/connectionquality/connectionquality';
|
import ConnectionQuality from './modules/connectionquality/connectionquality';
|
||||||
|
@ -26,7 +26,7 @@ const ConferenceErrors = JitsiMeetJS.errors.conference;
|
||||||
const TrackEvents = JitsiMeetJS.events.track;
|
const TrackEvents = JitsiMeetJS.events.track;
|
||||||
const TrackErrors = JitsiMeetJS.errors.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.
|
* Indicates whether the connection is interrupted or not.
|
||||||
|
@ -363,18 +363,7 @@ class ConferenceConnector {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
// room is locked by the password
|
// room is locked by the password
|
||||||
case ConferenceErrors.PASSWORD_REQUIRED:
|
case ConferenceErrors.PASSWORD_REQUIRED:
|
||||||
APP.UI.markRoomLocked(true);
|
APP.UI.emitEvent(UIEvents.PASSWORD_REQUIRED);
|
||||||
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);
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConferenceErrors.CONNECTION_ERROR:
|
case ConferenceErrors.CONNECTION_ERROR:
|
||||||
|
@ -403,8 +392,7 @@ class ConferenceConnector {
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
// notify user that auth is required
|
// notify user that auth is required
|
||||||
|
AuthHandler.requireAuth(room, this.invite.getRoomLocker().password);
|
||||||
AuthHandler.requireAuth(room, roomLocker.password);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ConferenceErrors.RESERVATION_ERROR:
|
case ConferenceErrors.RESERVATION_ERROR:
|
||||||
|
@ -576,6 +564,8 @@ export default {
|
||||||
this.isDesktopSharingEnabled =
|
this.isDesktopSharingEnabled =
|
||||||
JitsiMeetJS.isDesktopSharingEnabled();
|
JitsiMeetJS.isDesktopSharingEnabled();
|
||||||
|
|
||||||
|
APP.UI.ContactList = new ContactList(room);
|
||||||
|
|
||||||
// if user didn't give access to mic or camera or doesn't have
|
// if user didn't give access to mic or camera or doesn't have
|
||||||
// them at all, we disable corresponding toolbar buttons
|
// them at all, we disable corresponding toolbar buttons
|
||||||
if (!tracks.find((t) => t.isAudioTrack())) {
|
if (!tracks.find((t) => t.isAudioTrack())) {
|
||||||
|
@ -888,7 +878,7 @@ export default {
|
||||||
room = connection.initJitsiConference(APP.conference.roomName,
|
room = connection.initJitsiConference(APP.conference.roomName,
|
||||||
this._getConferenceOptions());
|
this._getConferenceOptions());
|
||||||
this._setLocalAudioVideoStreams(localTracks);
|
this._setLocalAudioVideoStreams(localTracks);
|
||||||
roomLocker = createRoomLocker(room);
|
this.invite = new Invite(room);
|
||||||
this._room = room; // FIXME do not use this
|
this._room = room; // FIXME do not use this
|
||||||
|
|
||||||
let email = APP.settings.getEmail();
|
let email = APP.settings.getEmail();
|
||||||
|
@ -1316,13 +1306,6 @@ export default {
|
||||||
APP.UI.updateRecordingState(status);
|
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) {
|
room.on(ConferenceEvents.USER_STATUS_CHANGED, function (id, status) {
|
||||||
APP.UI.updateUserStatus(id, status);
|
APP.UI.updateUserStatus(id, status);
|
||||||
});
|
});
|
||||||
|
@ -1348,19 +1331,6 @@ export default {
|
||||||
"resizable,scrollbars=yes,status=1");
|
"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.AUDIO_MUTED, muteLocalAudio);
|
||||||
APP.UI.addListener(UIEvents.VIDEO_MUTED, muteLocalVideo);
|
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;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
html, body, input, textarea, keygen, select, button {
|
html, body, input, textarea, keygen, select, button {
|
||||||
font-family: $baseFontFamily !important;
|
font-family: $baseFontFamily !important;
|
||||||
}
|
}
|
||||||
|
@ -26,16 +30,17 @@ html, body, input, textarea, keygen, select, button {
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='text'], input[type='password'], textarea {
|
input[type='text'], input[type='password'], textarea {
|
||||||
-webkit-user-select: text;
|
|
||||||
user-select: text;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 5px;
|
width: 100%;
|
||||||
color: $defaultDarkColor;
|
padding: 5px 7px;
|
||||||
|
color: $inputColor;
|
||||||
border-radius: $borderRadius;
|
border-radius: $borderRadius;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
|
letter-spacing: $letterSpacing;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border:1px solid $inputBorderColor;
|
border:1px solid $inputBorderColor;
|
||||||
|
background-color: $inputBackground;
|
||||||
outline: none; /* removes the default outline */
|
outline: none; /* removes the default outline */
|
||||||
resize: none; /* prevents the user-resizing, adjust to taste */
|
resize: none; /* prevents the user-resizing, adjust to taste */
|
||||||
}
|
}
|
||||||
|
@ -43,7 +48,8 @@ input[type='text'], input[type='password'], textarea {
|
||||||
textarea {
|
textarea {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
resize: horizontal;
|
resize: none;
|
||||||
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.no-icon {
|
button.no-icon {
|
||||||
|
@ -53,12 +59,9 @@ button.no-icon {
|
||||||
button, input, select, textarea {
|
button, input, select, textarea {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
color: $defaultDarkColor;
|
color: $inputColor;
|
||||||
background: $inputLightBackground;
|
font-size: 1em;
|
||||||
font-size: 12px;
|
letter-spacing: $letterSpacing;
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
outline: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button, select, input[type="button"],
|
button, select, input[type="button"],
|
||||||
|
@ -72,7 +75,7 @@ input[type="reset"], input[type="submit"] {
|
||||||
|
|
||||||
button {
|
button {
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
background-color: $buttonBackground !important;
|
background-color: $buttonBackground;
|
||||||
border-radius: $borderRadius;
|
border-radius: $borderRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +162,9 @@ form {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tooltips
|
||||||
|
**/
|
||||||
.tipsy {
|
.tipsy {
|
||||||
z-index: $tooltipsZ;
|
z-index: $tooltipsZ;
|
||||||
&-inner {
|
&-inner {
|
||||||
|
@ -169,3 +175,26 @@ form {
|
||||||
border-color: $tooltipBg;
|
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 {
|
> ul#contacts {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
margin: 0px;
|
margin: 0;
|
||||||
|
margin-top: 16px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -24,7 +25,7 @@
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
padding: 6px 10%;
|
padding: 6px 30px;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:active {
|
&: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;
|
animation: $animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin flex() {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -moz-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keyframes mixin.
|
* Keyframes mixin.
|
||||||
*/
|
*/
|
||||||
|
@ -63,3 +71,9 @@
|
||||||
-webkit-transition: $transition;
|
-webkit-transition: $transition;
|
||||||
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%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jqibuttons button {
|
|
||||||
margin-right: 5px;
|
|
||||||
float:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.jqidefaultbutton #inviteLinkRef {
|
button.jqidefaultbutton #inviteLinkRef {
|
||||||
color: #2c8ad2;
|
color: #2c8ad2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: $defaultToolbarSize;
|
left: $defaultToolbarSize;
|
||||||
width: 0%;
|
width: 0;
|
||||||
height: 100%;
|
|
||||||
max-width: 200px;
|
|
||||||
background-color: rgba(0,0,0,0.8);
|
background-color: rgba(0,0,0,0.8);
|
||||||
|
height: 100%;
|
||||||
|
max-width: $sidebarWidth;
|
||||||
z-index: 800;
|
z-index: 800;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
letter-spacing: 1px;
|
letter-spacing: $titleLetterSpacing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Labels inside the side panel.
|
* Labels inside the side panel.
|
||||||
|
@ -24,7 +24,8 @@
|
||||||
/**
|
/**
|
||||||
* Form elements and blocks.
|
* Form elements and blocks.
|
||||||
*/
|
*/
|
||||||
input, label, select, button, a, .sideToolbarBlock {
|
input, label, select, a,
|
||||||
|
.sideToolbarBlock, .input-control, .button-control {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
margin-left: 10%;
|
margin-left: 10%;
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
*/
|
*/
|
||||||
select, input[type="button"], input[type="text"],
|
select, input[type="button"], input[type="text"],
|
||||||
input[type="reset"], input[type="submit"] {
|
input[type="reset"], input[type="submit"] {
|
||||||
color: $defaultColor;
|
color: $inputColor;
|
||||||
background: $inputBackground;
|
background: $inputBackground;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,10 @@
|
||||||
*/
|
*/
|
||||||
.sideToolbarContainer__inner {
|
.sideToolbarContainer__inner {
|
||||||
display: none;
|
display: none;
|
||||||
width: 200px;
|
height: 100%;
|
||||||
|
width: $sidebarWidth;
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,6 +104,14 @@
|
||||||
.first {
|
.first {
|
||||||
margin-top: 0px !important;
|
margin-top: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buttons in the side toolbar container.
|
||||||
|
*/
|
||||||
|
.button-control {
|
||||||
|
margin: 9px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,13 +45,13 @@
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|
||||||
.first {
|
.first {
|
||||||
border-bottom-left-radius: 4px;
|
border-bottom-left-radius: 3px;
|
||||||
border-top-left-radius: 4px;
|
border-top-left-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.last {
|
.last {
|
||||||
border-bottom-right-radius: 4px;
|
border-bottom-right-radius: 3px;
|
||||||
border-top-right-radius: 4px;
|
border-top-right-radius: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Theme
|
||||||
|
*/
|
||||||
|
@import 'themes/light';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Style variables
|
* Style variables
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +26,8 @@ $thumbnailToolbarHeight: 25px;
|
||||||
*/
|
*/
|
||||||
$defaultColor: #F1F1F1;
|
$defaultColor: #F1F1F1;
|
||||||
$defaultSideBarFontColor: #44A5FF;
|
$defaultSideBarFontColor: #44A5FF;
|
||||||
$defaultDarkColor: #4F4F4F;
|
$defaultSemiDarkColor: #ACACAC;
|
||||||
|
$defaultDarkColor: #2b3d5c;
|
||||||
$defaultBackground: #474747;
|
$defaultBackground: #474747;
|
||||||
$tooltipBg: rgba(0,0,0, 0.7);
|
$tooltipBg: rgba(0,0,0, 0.7);
|
||||||
|
|
||||||
|
@ -33,11 +39,8 @@ $toolbarBadgeColor: #FFFFFF;
|
||||||
$toolbarToggleBackground: #12499C;
|
$toolbarToggleBackground: #12499C;
|
||||||
|
|
||||||
// Main controls
|
// Main controls
|
||||||
$inputBackground: rgba(132, 132, 132, .5);
|
|
||||||
$inputSemiBackground: rgba(132, 132, 132, .8);
|
$inputSemiBackground: rgba(132, 132, 132, .8);
|
||||||
$inputLightBackground: #EBEBEB;
|
$inputLightBackground: #EBEBEB;
|
||||||
$inputBorderColor: #EBEBEB;
|
|
||||||
$buttonBackground: #44A5FF;
|
|
||||||
|
|
||||||
// Video layout.
|
// Video layout.
|
||||||
$videoThumbnailHovered: #BFEBFF;
|
$videoThumbnailHovered: #BFEBFF;
|
||||||
|
@ -58,10 +61,25 @@ $rateStarLabelColor: #333;
|
||||||
*/
|
*/
|
||||||
$borderRadius: 4px;
|
$borderRadius: 4px;
|
||||||
$defaultWatermarkLink: '../images/watermark.png';
|
$defaultWatermarkLink: '../images/watermark.png';
|
||||||
|
$sidebarWidth: 200px;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Z-indexes. TODO: Replace this by a function.
|
* Z-indexes. TODO: Replace this by a function.
|
||||||
*/
|
*/
|
||||||
$tooltipsZ: 901;
|
$tooltipsZ: 901;
|
||||||
$toolbarZ: 900;
|
$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 */
|
/* Variables BEGIN */
|
||||||
|
|
||||||
@import 'variables';
|
@import 'variables';
|
||||||
|
@ -10,6 +16,12 @@
|
||||||
|
|
||||||
/* Mixins END */
|
/* Mixins END */
|
||||||
|
|
||||||
|
/* Animations BEGIN */
|
||||||
|
|
||||||
|
@import "animations";
|
||||||
|
|
||||||
|
/* Animations END */
|
||||||
|
|
||||||
/* Fonts BEGIN */
|
/* Fonts BEGIN */
|
||||||
|
|
||||||
@import 'font';
|
@import 'font';
|
||||||
|
@ -17,6 +29,10 @@
|
||||||
|
|
||||||
/* Fonts END */
|
/* Fonts END */
|
||||||
|
|
||||||
|
/* Theme BEGIN */
|
||||||
|
@import "themes/light";
|
||||||
|
/* Theme END */
|
||||||
|
|
||||||
/* Modules BEGIN */
|
/* Modules BEGIN */
|
||||||
|
|
||||||
@import 'toastr';
|
@import 'toastr';
|
||||||
|
@ -25,8 +41,6 @@
|
||||||
@import 'modals/dialog';
|
@import 'modals/dialog';
|
||||||
@import 'modals/feedback/feedback';
|
@import 'modals/feedback/feedback';
|
||||||
@import 'videolayout_default';
|
@import 'videolayout_default';
|
||||||
@import 'jquery-impromptu';
|
|
||||||
@import 'modaldialog';
|
|
||||||
@import 'notice';
|
@import 'notice';
|
||||||
@import 'popup_menu';
|
@import 'popup_menu';
|
||||||
@import 'recording';
|
@import 'recording';
|
||||||
|
@ -43,6 +57,8 @@
|
||||||
@import 'jquery.contextMenu';
|
@import 'jquery.contextMenu';
|
||||||
@import 'keyboard-shortcuts';
|
@import 'keyboard-shortcuts';
|
||||||
@import 'redirect_page';
|
@import 'redirect_page';
|
||||||
|
@import 'input-control/input-control';
|
||||||
|
@import 'shortcuts/main';
|
||||||
|
@import 'buttons/button-control';
|
||||||
|
|
||||||
/* Modules END */
|
/* Modules END */
|
|
@ -1,53 +1,80 @@
|
||||||
.dialog{
|
.dialog {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
p {
|
h3 {
|
||||||
color: $defaultDarkColor;
|
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 {
|
.aui {
|
||||||
font-weight: 400 !important;
|
|
||||||
color: $buttonBackground;
|
|
||||||
background: none !important;
|
|
||||||
|
|
||||||
:hover {
|
&-icon {
|
||||||
text-decoration: underline;
|
color: $auiDialogColor;
|
||||||
|
|
||||||
|
&-small {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&_submit {
|
|
||||||
font-weight: 700 !important;
|
&-iconfont-close-dialog {
|
||||||
color: $defaultColor;
|
cursor: pointer;
|
||||||
background: $buttonBackground;
|
right: 20px;
|
||||||
border-radius: 3px;
|
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
|
animation-timing-function: ease-in-out
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback {
|
.feedback.aui-dialog2{
|
||||||
h2 {
|
.aui-dialog2{
|
||||||
font-weight: 400;
|
&-header {
|
||||||
font-size: 24px;
|
background-color: $auiDialogContentBg;
|
||||||
line-height: 1.2;
|
border-bottom-color: transparent;
|
||||||
}
|
padding-top: 30px;
|
||||||
p {
|
h2 {
|
||||||
font-weight: 400;
|
text-align: center;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.star-label {
|
&-content {
|
||||||
font-size: 16px;
|
text-align: center;
|
||||||
color: $rateStarLabelColor;
|
padding: 10px 40px 20px 40px;
|
||||||
}
|
|
||||||
|
|
||||||
.star-btn {
|
.rating {
|
||||||
color: $rateStarDefault;
|
line-height: 1.2;
|
||||||
font-size: 36px;
|
text-align: center;
|
||||||
position: relative;
|
margin-top: 10px;
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
text-decoration: none;
|
|
||||||
@include transition(all .2s ease);
|
|
||||||
|
|
||||||
&.starHover,
|
.star-label {
|
||||||
&.active,
|
height: 16px;
|
||||||
&:hover {
|
font-size: 14px;
|
||||||
color: $rateStarActivity;
|
|
||||||
> i:before {
|
|
||||||
content: "\e90a";
|
|
||||||
}
|
}
|
||||||
};
|
.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>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a class="button" id="toolbar_button_record" style="display: none"></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-share-doc" id="toolbar_button_etherpad"></a>
|
||||||
<a class="button icon-shared-video" id="toolbar_button_sharedvideo" style="display: none">
|
<a class="button icon-shared-video" id="toolbar_button_sharedvideo" style="display: none">
|
||||||
<ul id="sharedVideoMutedPopup" class="loginmenu extendedToolbarPopup">
|
<ul id="sharedVideoMutedPopup" class="loginmenu extendedToolbarPopup">
|
||||||
|
@ -254,12 +253,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
||||||
<div class="header"><h3 data-i18n="keyboardShortcuts.keyboardShortcuts"></h3></div>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul id="keyboard-shortcuts-list" class="item">
|
<ul id="keyboard-shortcuts-list" class="shortcuts-list">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="aui-feedback-dialog" class="dialog feedback aui-layer aui-dialog2 aui-dialog2-medium" style="display: none;"></div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -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",
|
"connectionsettings": "Connection Settings",
|
||||||
"poweredby": "powered by",
|
"poweredby": "powered by",
|
||||||
"feedback": "Give us your feedback",
|
"feedback": "Give us your feedback",
|
||||||
"roomUrlDefaultMsg": "Your conference is currently being created...",
|
"inviteUrlDefaultMsg": "Your conference is currently being created...",
|
||||||
"me": "me",
|
"me": "me",
|
||||||
"speaker": "Speaker",
|
"speaker": "Speaker",
|
||||||
"raisedHand": "Would like to speak",
|
"raisedHand": "Would like to speak",
|
||||||
|
@ -180,8 +184,10 @@
|
||||||
"raisedHand": "Would like to speak."
|
"raisedHand": "Would like to speak."
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
"add": "Add",
|
||||||
"kickMessage": "Ouch! You have been kicked out of the meet!",
|
"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.",
|
"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.",
|
"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.",
|
"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.",
|
"connectError": "Oops! Something went wrong and we couldn't connect to the conference.",
|
||||||
|
@ -189,6 +195,7 @@
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
|
"addPassword": "Add Password",
|
||||||
"detectext": "Error when trying to detect desktopsharing extension.",
|
"detectext": "Error when trying to detect desktopsharing extension.",
|
||||||
"failtoinstall": "Failed to install desktop sharing extension",
|
"failtoinstall": "Failed to install desktop sharing extension",
|
||||||
"failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.",
|
"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)",
|
"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)",
|
"SRDFailure": "Oops! Something went wrong and we failed to stop video! (SRD Failure)",
|
||||||
"oops": "Oops!",
|
"oops": "Oops!",
|
||||||
|
"currentPassword": "The current password is",
|
||||||
|
"passwordLabel": "Password",
|
||||||
"defaultError": "There was some kind of error",
|
"defaultError": "There was some kind of error",
|
||||||
"passwordRequired": "Password required",
|
"passwordRequired": "Password required",
|
||||||
"Ok": "Ok",
|
"Ok": "Ok",
|
||||||
"Remove": "Remove",
|
"Remove": "Remove",
|
||||||
|
"removePassword": "Remove password",
|
||||||
"shareVideoTitle": "Share a video",
|
"shareVideoTitle": "Share a video",
|
||||||
"shareVideoLinkError": "Please provide a correct youtube link.",
|
"shareVideoLinkError": "Please provide a correct youtube link.",
|
||||||
"removeSharedVideoTitle": "Remove shared video",
|
"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.",
|
"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",
|
"IamHost": "I am the host",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
|
"Submit": "Submit",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
"logoutTitle" : "Logout",
|
"logoutTitle" : "Logout",
|
||||||
"logoutQuestion" : "Are you sure you want to logout and stop the conference?",
|
"logoutQuestion" : "Are you sure you want to logout and stop the conference?",
|
||||||
|
@ -231,7 +242,6 @@
|
||||||
"Dial": "Dial",
|
"Dial": "Dial",
|
||||||
"sipMsg": "Enter SIP number",
|
"sipMsg": "Enter SIP number",
|
||||||
"passwordCheck": "Are you sure you would like to remove your password?",
|
"passwordCheck": "Are you sure you would like to remove your password?",
|
||||||
"Remove": "Remove",
|
|
||||||
"passwordMsg": "Set a password to lock your room",
|
"passwordMsg": "Set a password to lock your room",
|
||||||
"shareLink": "Copy and share this link",
|
"shareLink": "Copy and share this link",
|
||||||
"settings1": "Configure your conference",
|
"settings1": "Configure your conference",
|
||||||
|
|
119
modules/UI/UI.js
119
modules/UI/UI.js
|
@ -4,7 +4,6 @@ var UI = {};
|
||||||
import Chat from "./side_pannels/chat/Chat";
|
import Chat from "./side_pannels/chat/Chat";
|
||||||
import Toolbar from "./toolbars/Toolbar";
|
import Toolbar from "./toolbars/Toolbar";
|
||||||
import ToolbarToggler from "./toolbars/ToolbarToggler";
|
import ToolbarToggler from "./toolbars/ToolbarToggler";
|
||||||
import ContactList from "./side_pannels/contactlist/ContactList";
|
|
||||||
import Avatar from "./avatar/Avatar";
|
import Avatar from "./avatar/Avatar";
|
||||||
import SideContainerToggler from "./side_pannels/SideContainerToggler";
|
import SideContainerToggler from "./side_pannels/SideContainerToggler";
|
||||||
import UIUtil from "./util/UIUtil";
|
import UIUtil from "./util/UIUtil";
|
||||||
|
@ -29,7 +28,6 @@ UI.messageHandler = require("./util/MessageHandler");
|
||||||
var messageHandler = UI.messageHandler;
|
var messageHandler = UI.messageHandler;
|
||||||
var JitsiPopover = require("./util/JitsiPopover");
|
var JitsiPopover = require("./util/JitsiPopover");
|
||||||
var Feedback = require("./feedback/Feedback");
|
var Feedback = require("./feedback/Feedback");
|
||||||
|
|
||||||
import FollowMe from "../FollowMe";
|
import FollowMe from "../FollowMe";
|
||||||
|
|
||||||
var eventEmitter = new EventEmitter();
|
var eventEmitter = new EventEmitter();
|
||||||
|
@ -242,7 +240,7 @@ UI.showChatError = function (err, msg) {
|
||||||
* @param {string} displayName new nickname
|
* @param {string} displayName new nickname
|
||||||
*/
|
*/
|
||||||
UI.changeDisplayName = function (id, displayName) {
|
UI.changeDisplayName = function (id, displayName) {
|
||||||
ContactList.onDisplayNameChange(id, displayName);
|
UI.ContactList.onDisplayNameChange(id, displayName);
|
||||||
VideoLayout.onDisplayNameChanged(id, displayName);
|
VideoLayout.onDisplayNameChanged(id, displayName);
|
||||||
|
|
||||||
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
|
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
|
||||||
|
@ -292,14 +290,16 @@ UI.initConference = function () {
|
||||||
// "https:" + "//" + "example.com:8888" + "/SomeConference1245"
|
// "https:" + "//" + "example.com:8888" + "/SomeConference1245"
|
||||||
var inviteURL = window.location.protocol + "//" +
|
var inviteURL = window.location.protocol + "//" +
|
||||||
window.location.host + window.location.pathname;
|
window.location.host + window.location.pathname;
|
||||||
Toolbar.updateRoomUrl(inviteURL);
|
|
||||||
|
this.emitEvent(UIEvents.INVITE_URL_INITIALISED, inviteURL);
|
||||||
|
|
||||||
// Clean up the URL displayed by the browser
|
// Clean up the URL displayed by the browser
|
||||||
if (window.history && typeof window.history.replaceState === 'function') {
|
if (window.history && typeof window.history.replaceState === 'function') {
|
||||||
window.history.replaceState({}, document.title, inviteURL);
|
window.history.replaceState({}, document.title, inviteURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add myself to the contact list.
|
// Add myself to the contact list.
|
||||||
ContactList.addContact(id, true);
|
UI.ContactList.addContact(id, true);
|
||||||
|
|
||||||
// Update default button states before showing the toolbar
|
// Update default button states before showing the toolbar
|
||||||
// if local role changes buttons state will be again updated.
|
// if local role changes buttons state will be again updated.
|
||||||
|
@ -470,8 +470,6 @@ UI.start = function () {
|
||||||
}
|
}
|
||||||
VideoLayout.resizeVideoArea(true, true);
|
VideoLayout.resizeVideoArea(true, true);
|
||||||
|
|
||||||
ContactList.init(eventEmitter);
|
|
||||||
|
|
||||||
bindEvents();
|
bindEvents();
|
||||||
sharedVideoManager = new SharedVideoManager(eventEmitter);
|
sharedVideoManager = new SharedVideoManager(eventEmitter);
|
||||||
if (!interfaceConfig.filmStripOnly) {
|
if (!interfaceConfig.filmStripOnly) {
|
||||||
|
@ -608,7 +606,7 @@ UI.addUser = function (user) {
|
||||||
var id = user.getId();
|
var id = user.getId();
|
||||||
var displayName = user.getDisplayName();
|
var displayName = user.getDisplayName();
|
||||||
UI.hideRingOverLay();
|
UI.hideRingOverLay();
|
||||||
ContactList.addContact(id);
|
UI.ContactList.addContact(id);
|
||||||
|
|
||||||
messageHandler.notify(
|
messageHandler.notify(
|
||||||
displayName,'notify.somebody', 'connected', 'notify.connected'
|
displayName,'notify.somebody', 'connected', 'notify.connected'
|
||||||
|
@ -635,7 +633,7 @@ UI.addUser = function (user) {
|
||||||
* @param {string} displayName user nickname
|
* @param {string} displayName user nickname
|
||||||
*/
|
*/
|
||||||
UI.removeUser = function (id, displayName) {
|
UI.removeUser = function (id, displayName) {
|
||||||
ContactList.removeContact(id);
|
UI.ContactList.removeContact(id);
|
||||||
|
|
||||||
messageHandler.notify(
|
messageHandler.notify(
|
||||||
displayName,'notify.somebody', 'disconnected', 'notify.disconnected'
|
displayName,'notify.somebody', 'disconnected', 'notify.disconnected'
|
||||||
|
@ -786,28 +784,33 @@ UI.connectionIndicatorShowMore = function(id) {
|
||||||
// FIXME check if someone user this
|
// FIXME check if someone user this
|
||||||
UI.showLoginPopup = function(callback) {
|
UI.showLoginPopup = function(callback) {
|
||||||
console.log('password is required');
|
console.log('password is required');
|
||||||
var message = '<h2 data-i18n="dialog.passwordRequired">';
|
let titleKey = "dialog.passwordRequired";
|
||||||
message += APP.translation.translateString(
|
let titleString = APP.translation.translateString(titleKey);
|
||||||
"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 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 () {
|
UI.askForNickname = function () {
|
||||||
|
@ -888,7 +891,7 @@ UI.dockToolbar = function (isDock) {
|
||||||
*/
|
*/
|
||||||
function changeAvatar(id, avatarUrl) {
|
function changeAvatar(id, avatarUrl) {
|
||||||
VideoLayout.changeUserAvatar(id, avatarUrl);
|
VideoLayout.changeUserAvatar(id, avatarUrl);
|
||||||
ContactList.changeUserAvatar(id, avatarUrl);
|
UI.ContactList.changeUserAvatar(id, avatarUrl);
|
||||||
if (APP.conference.isLocalId(id)) {
|
if (APP.conference.isLocalId(id)) {
|
||||||
Profile.changeAvatar(avatarUrl);
|
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.
|
* Add chat message.
|
||||||
* @param {string} from user id
|
* @param {string} from user id
|
||||||
|
@ -1254,24 +1245,27 @@ UI.showExtensionRequiredDialog = function (url) {
|
||||||
* @param url {string} the url of the extension.
|
* @param url {string} the url of the extension.
|
||||||
*/
|
*/
|
||||||
UI.showExtensionExternalInstallationDialog = function (url) {
|
UI.showExtensionExternalInstallationDialog = function (url) {
|
||||||
messageHandler.openTwoButtonDialog(
|
let submitFunction = function(e,v){
|
||||||
"dialog.externalInstallationTitle",
|
if (v) {
|
||||||
null,
|
e.preventDefault();
|
||||||
"dialog.externalInstallationMsg",
|
eventEmitter.emit(UIEvents.OPEN_EXTENSION_STORE, url);
|
||||||
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 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.'
|
* Shows or hides the keyboard shortcuts panel, depending on the current state.'
|
||||||
*/
|
*/
|
||||||
UI.toggleKeyboardShortcutsPanel = function() {
|
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 */
|
/* global $, APP, JitsiMeetJS */
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from "../../../service/UI/UIEvents";
|
||||||
import FeedabckWindow from "./FeedbackWindow";
|
import FeedbackWindow from "./FeedbackWindow";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows / hides the feedback button.
|
* Shows / hides the feedback button.
|
||||||
|
@ -49,7 +49,7 @@ var Feedback = {
|
||||||
|
|
||||||
_showFeedbackButton(this.enabled);
|
_showFeedbackButton(this.enabled);
|
||||||
|
|
||||||
this.window = new FeedabckWindow({});
|
this.window = new FeedbackWindow();
|
||||||
|
|
||||||
$("#feedbackButton").click(Feedback.openFeedbackWindow);
|
$("#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
|
* 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
|
* @param starCount the number of stars, for which to toggle the css class
|
||||||
*/
|
*/
|
||||||
function toggleStars(starCount) {
|
function toggleStars(starCount) {
|
||||||
|
let labelEl = $('#starLabel');
|
||||||
|
let label = starCount >= 0 ?
|
||||||
|
labels[starCount + 1] :
|
||||||
|
'';
|
||||||
|
|
||||||
$('#stars > a').each(function(index, el) {
|
$('#stars > a').each(function(index, el) {
|
||||||
if (index <= starCount) {
|
if (index <= starCount) {
|
||||||
el.classList.add("starHover");
|
el.classList.add("starHover");
|
||||||
} else
|
} else
|
||||||
el.classList.remove("starHover");
|
el.classList.remove("starHover");
|
||||||
});
|
});
|
||||||
|
labelEl.text(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,63 +35,51 @@ function toggleStars(starCount) {
|
||||||
* @returns {string} the contructed html string
|
* @returns {string} the contructed html string
|
||||||
*/
|
*/
|
||||||
function createRateFeedbackHTML() {
|
function createRateFeedbackHTML() {
|
||||||
let rateExperience
|
let feedbackHelp = APP.translation.translateString('dialog.feedbackHelp');
|
||||||
= APP.translation.translateString('dialog.rateExperience'),
|
|
||||||
feedbackHelp = APP.translation.translateString('dialog.feedbackHelp');
|
|
||||||
|
|
||||||
let starClassName = (interfaceConfig.ENABLE_FEEDBACK_ANIMATION)
|
let starClassName = (interfaceConfig.ENABLE_FEEDBACK_ANIMATION)
|
||||||
? "icon-star shake-rotate"
|
? "icon-star-full shake-rotate"
|
||||||
: "icon-star";
|
: "icon-star-full";
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="aui-dialog2-content feedback__content">
|
<form id="feedbackForm"
|
||||||
<form action="javascript:false;" onsubmit="return false;">
|
action="javascript:false;" onsubmit="return false;">
|
||||||
<div class="feedback__rating">
|
<div class="rating">
|
||||||
<h2>${ rateExperience }</h2>
|
<div class="star-label">
|
||||||
<p class="star-label"> </p>
|
<p id="starLabel"> </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>
|
|
||||||
</div>
|
</div>
|
||||||
<textarea id="feedbackTextArea" rows="10" cols="40" autofocus>
|
<div id="stars" class="feedback-stars">
|
||||||
</textarea>
|
<a class="star-btn">
|
||||||
</form>
|
<i class=${ starClassName }></i>
|
||||||
<footer class="aui-dialog2-footer feedback__footer">
|
</a>
|
||||||
<div class="aui-dialog2-footer-actions">
|
<a class="star-btn">
|
||||||
<button
|
<i class=${ starClassName }></i>
|
||||||
id="dialog-close-button"
|
</a>
|
||||||
class="aui-button aui-button_close">Close</button>
|
<a class="star-btn">
|
||||||
<button
|
<i class=${ starClassName }></i>
|
||||||
id="dialog-submit-button"
|
</a>
|
||||||
class="aui-button aui-button_submit">Submit</button>
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
|
<a class="star-btn">
|
||||||
|
<i class=${ starClassName }></i>
|
||||||
|
</a>
|
||||||
</div>
|
</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
|
* @param Feedback
|
||||||
*/
|
*/
|
||||||
let onLoadRateFunction = function (Feedback) {
|
let onLoadFunction = function (Feedback) {
|
||||||
$('#stars > a').each((index, el) => {
|
$('#stars > a').each((index, el) => {
|
||||||
el.onmouseover = function(){
|
el.onmouseover = function(){
|
||||||
toggleStars(index);
|
toggleStars(index);
|
||||||
|
@ -89,6 +89,7 @@ let onLoadRateFunction = function (Feedback) {
|
||||||
};
|
};
|
||||||
el.onclick = function(){
|
el.onclick = function(){
|
||||||
Feedback.feedbackScore = index + 1;
|
Feedback.feedbackScore = index + 1;
|
||||||
|
Feedback.setFeedbackMessage();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -97,101 +98,88 @@ let onLoadRateFunction = function (Feedback) {
|
||||||
toggleStars(Feedback.feedbackScore - 1);
|
toggleStars(Feedback.feedbackScore - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Feedback.feedbackText && Feedback.feedbackText.length > 0)
|
if (Feedback.feedbackMessage && Feedback.feedbackMessage.length > 0)
|
||||||
$('#feedbackTextArea').text(Feedback.feedbackText);
|
$('#feedbackTextArea').text(Feedback.feedbackMessage);
|
||||||
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#feedbackTextArea').focus();
|
$('#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
|
* @class Dialog
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default class Dialog {
|
export default class Dialog {
|
||||||
|
|
||||||
constructor(options) {
|
constructor() {
|
||||||
this.feedbackScore = -1;
|
this.feedbackScore = -1;
|
||||||
this.feedbackText = null;
|
this.feedbackMessage = '';
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
this.onCloseCallback = null;
|
this.onCloseCallback = function() {};
|
||||||
|
|
||||||
this.states = {
|
this.setDefoulOptions();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(state) {
|
setDefoulOptions() {
|
||||||
let newState = state || this.state;
|
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) {
|
show(cb) {
|
||||||
this.setState('rate_feedback');
|
const options = this.options;
|
||||||
if (typeof cb == 'function') {
|
if (typeof cb === 'function') {
|
||||||
this.onCloseCallback = cb;
|
this.onCloseCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.window.show();
|
this.window = APP.UI.messageHandler.openTwoButtonDialog(options);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
onHide() {
|
||||||
this.window.hide();
|
this.onCloseCallback(this.feedbackScore, this.feedbackMessage);
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, role) => {
|
||||||
|
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) {
|
return new Promise(function (resolve, reject) {
|
||||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||||
state0: {
|
state0: {
|
||||||
|
title: msg,
|
||||||
html:
|
html:
|
||||||
`<h2>${msg}</h2>
|
`<input name="streamId" type="text"
|
||||||
<input name="streamId" type="text"
|
|
||||||
data-i18n="[placeholder]dialog.streamKey"
|
data-i18n="[placeholder]dialog.streamKey"
|
||||||
placeholder="${token}" autofocus>`,
|
placeholder="${token}" autofocus>`,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
|
@ -89,7 +89,8 @@ function _requestLiveStreamId() {
|
||||||
},
|
},
|
||||||
|
|
||||||
state1: {
|
state1: {
|
||||||
html: `<h2>${msg}</h2> ${streamIdRequired}`,
|
title: msg,
|
||||||
|
html: streamIdRequired,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{title: cancelButton, value: false},
|
||||||
|
@ -120,30 +121,30 @@ function _requestLiveStreamId() {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function _requestRecordingToken () {
|
function _requestRecordingToken () {
|
||||||
let msg = APP.translation.generateTranslationHTML("dialog.recordingToken");
|
let titleKey = "dialog.recordingToken";
|
||||||
let token = APP.translation.translateString("dialog.token");
|
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) {
|
return new Promise(function (resolve, reject) {
|
||||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
null, null, null,
|
titleKey,
|
||||||
`<h2>${msg}</h2>
|
messageString,
|
||||||
<input name="recordingToken" type="text"
|
leftButtonKey: 'dialog.Save',
|
||||||
data-i18n="[placeholder]dialog.token"
|
submitFunction: function (e, v, m, f) {
|
||||||
placeholder="${token}" autofocus>`,
|
|
||||||
false, "dialog.Save",
|
|
||||||
function (e, v, m, f) {
|
|
||||||
if (v && f.recordingToken) {
|
if (v && f.recordingToken) {
|
||||||
resolve(UIUtil.escapeHtml(f.recordingToken));
|
resolve(UIUtil.escapeHtml(f.recordingToken));
|
||||||
} else {
|
} else {
|
||||||
reject(APP.UI.messageHandler.CANCEL);
|
reject(APP.UI.messageHandler.CANCEL);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
closeFunction: function () {
|
||||||
function () {
|
|
||||||
dialog = null;
|
dialog = null;
|
||||||
},
|
},
|
||||||
':input:first'
|
focus: ':input:first'
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,25 +171,21 @@ function _showStopRecordingPrompt (recordingType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
title,
|
titleKey: title,
|
||||||
null,
|
messageKey: message,
|
||||||
message,
|
leftButtonKey: buttonKey,
|
||||||
null,
|
submitFunction: function(e,v) {
|
||||||
false,
|
|
||||||
buttonKey,
|
|
||||||
function(e,v) {
|
|
||||||
if (v) {
|
if (v) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
closeFunction: function () {
|
||||||
function () {
|
|
||||||
dialog = null;
|
dialog = null;
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -722,26 +722,25 @@ function getYoutubeLink(url) {
|
||||||
*/
|
*/
|
||||||
function showStopVideoPropmpt() {
|
function showStopVideoPropmpt() {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
dialog = APP.UI.messageHandler.openTwoButtonDialog(
|
let submitFunction = function(e,v) {
|
||||||
"dialog.removeSharedVideoTitle",
|
if (v) {
|
||||||
null,
|
resolve();
|
||||||
"dialog.removeSharedVideoMsg",
|
} else {
|
||||||
null,
|
reject();
|
||||||
false,
|
|
||||||
"dialog.Remove",
|
|
||||||
function(e,v) {
|
|
||||||
if (v) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
function () {
|
|
||||||
dialog = null;
|
|
||||||
}
|
}
|
||||||
);
|
};
|
||||||
|
|
||||||
|
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) {
|
return new Promise(function (resolve, reject) {
|
||||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||||
state0: {
|
state0: {
|
||||||
|
title: title,
|
||||||
html: `
|
html: `
|
||||||
<h2>${title}</h2>
|
|
||||||
<input name="sharedVideoUrl" type="text"
|
<input name="sharedVideoUrl" type="text"
|
||||||
data-i18n="[placeholder]defaultLink"
|
data-i18n="[placeholder]defaultLink"
|
||||||
data-i18n-options="${JSON.stringify(i18nOptions)}"
|
data-i18n-options="${JSON.stringify(i18nOptions)}"
|
||||||
|
@ -803,7 +802,8 @@ function requestVideoLink() {
|
||||||
},
|
},
|
||||||
|
|
||||||
state1: {
|
state1: {
|
||||||
html: `<h2>${title}</h2> ${linkError}`,
|
title: title,
|
||||||
|
html: linkError,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{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 */
|
/* global APP */
|
||||||
import Avatar from '../../avatar/Avatar';
|
|
||||||
import UIEvents from '../../../../service/UI/UIEvents';
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
import UIUtil from '../../util/UIUtil';
|
import ContactListView from './ContactListView';
|
||||||
|
import Contact from './Contact';
|
||||||
let numberOfContacts = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the number of participants in the contact list button and sets
|
* Model for the Contact list.
|
||||||
* the glow
|
*
|
||||||
* @param delta indicates whether a new user has joined (1) or someone has
|
* @class ContactList
|
||||||
* left(-1)
|
|
||||||
*/
|
*/
|
||||||
function updateNumberOfParticipants(delta) {
|
class ContactList {
|
||||||
numberOfContacts += delta;
|
constructor(conference) {
|
||||||
|
this.conference = conference;
|
||||||
if (numberOfContacts <= 0) {
|
this.contacts = [];
|
||||||
console.error("Invalid number of participants: " + numberOfContacts);
|
this.roomLocked = false;
|
||||||
return;
|
ContactListView.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#numberOfParticipants").text(numberOfContacts);
|
/**
|
||||||
|
* Is locked flag.
|
||||||
$("#contacts_container>div.title").text(
|
* Delegates to Invite module
|
||||||
APP.translation.translateString("contactlist")
|
* TO FIX: find a better way to access the IS LOCKED state of the invite.
|
||||||
+ ' (' + numberOfContacts + ')');
|
*
|
||||||
}
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
/**
|
isLocked() {
|
||||||
* Creates the avatar element.
|
return APP.conference.invite.isLocked();
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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> -
|
* @param id
|
||||||
* otherwise
|
* @param isLocal
|
||||||
*/
|
*/
|
||||||
isVisible () {
|
addContact(id, isLocal) {
|
||||||
return UIUtil.isVisible(document.getElementById("contactlist"));
|
let isExist = this.contacts.some((el) => el.id === id);
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
if (!isExist) {
|
||||||
* Adds a contact for the given id.
|
let newContact = new Contact({ id, isLocal });
|
||||||
* @param isLocal is an id for the local user.
|
this.contacts.push(newContact);
|
||||||
*/
|
APP.UI.emitEvent(UIEvents.CONTACT_ADDED, { id, isLocal });
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
updateNumberOfParticipants(1);
|
}
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a contact for the given id.
|
* Removing participant.
|
||||||
*
|
*
|
||||||
|
* @param id
|
||||||
|
* @returns {Array|*}
|
||||||
*/
|
*/
|
||||||
removeContact (id) {
|
removeContact(id) {
|
||||||
let contact = getContactEl(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();
|
* Changing the display name.
|
||||||
updateNumberOfParticipants(-1);
|
*
|
||||||
}
|
* @param id
|
||||||
},
|
* @param name
|
||||||
|
*/
|
||||||
setClickable (id, isClickable) {
|
onDisplayNameChange (id, name) {
|
||||||
getContactEl(id).toggleClass('clickable', isClickable);
|
if(!name)
|
||||||
},
|
|
||||||
|
|
||||||
onDisplayNameChange (id, displayName) {
|
|
||||||
if(!displayName)
|
|
||||||
return;
|
return;
|
||||||
if (id === 'localVideoContainer') {
|
if (id === 'localVideoContainer') {
|
||||||
id = APP.conference.getMyUserId();
|
id = APP.conference.getMyUserId();
|
||||||
}
|
}
|
||||||
let contactName = $(`#contacts #${id}>p`);
|
|
||||||
|
|
||||||
if (contactName.text() !== displayName) {
|
let contacts = this.contacts.filter((el) => el.id === id);
|
||||||
contactName.text(displayName);
|
contacts.forEach((el) => {
|
||||||
}
|
el.name = name;
|
||||||
},
|
});
|
||||||
|
APP.UI.emitEvent(UIEvents.DISPLAY_NAME_CHANGED, { id, name });
|
||||||
changeUserAvatar (id, avatarUrl) {
|
|
||||||
// set the avatar in the contact list
|
|
||||||
let contact = $(`#${id}>img`);
|
|
||||||
if (contact.length > 0) {
|
|
||||||
contact.attr('src', avatarUrl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
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,262 @@
|
||||||
|
/* 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 model = this.model;
|
||||||
|
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 UIEvents from '../../../service/UI/UIEvents';
|
||||||
import SideContainerToggler from "../side_pannels/SideContainerToggler";
|
import SideContainerToggler from "../side_pannels/SideContainerToggler";
|
||||||
|
|
||||||
let roomUrl = null;
|
|
||||||
let emitter = null;
|
let emitter = null;
|
||||||
|
let Toolbar;
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttonHandlers = {
|
const buttonHandlers = {
|
||||||
"toolbar_button_profile": function () {
|
"toolbar_button_profile": function () {
|
||||||
|
@ -98,13 +42,9 @@ const buttonHandlers = {
|
||||||
emitter.emit(UIEvents.VIDEO_MUTED, true);
|
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 () {
|
"toolbar_button_link": function () {
|
||||||
JitsiMeetJS.analytics.sendEvent('toolbar.invite.clicked');
|
JitsiMeetJS.analytics.sendEvent('toolbar.invite.clicked');
|
||||||
openLinkDialog();
|
emitter.emit(UIEvents.INVITE_CLICKED);
|
||||||
},
|
},
|
||||||
"toolbar_button_chat": function () {
|
"toolbar_button_chat": function () {
|
||||||
JitsiMeetJS.analytics.sendEvent('toolbar.chat.toggled');
|
JitsiMeetJS.analytics.sendEvent('toolbar.chat.toggled');
|
||||||
|
@ -158,21 +98,20 @@ const buttonHandlers = {
|
||||||
emitter.emit(UIEvents.AUTH_CLICKED);
|
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||||
},
|
},
|
||||||
"toolbar_button_logout": function () {
|
"toolbar_button_logout": function () {
|
||||||
|
let titleKey = "dialog.logoutTitle";
|
||||||
|
let msgKey = "dialog.logoutQuestion";
|
||||||
JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.logout.clicked');
|
JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.logout.clicked');
|
||||||
// Ask for confirmation
|
// Ask for confirmation
|
||||||
APP.UI.messageHandler.openTwoButtonDialog(
|
APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
"dialog.logoutTitle",
|
titleKey,
|
||||||
null,
|
msgKey,
|
||||||
"dialog.logoutQuestion",
|
leftButtonKey: "dialog.Yes",
|
||||||
null,
|
submitFunction: function (evt, yes) {
|
||||||
false,
|
|
||||||
"dialog.Yes",
|
|
||||||
function (evt, yes) {
|
|
||||||
if (yes) {
|
if (yes) {
|
||||||
emitter.emit(UIEvents.LOGOUT);
|
emitter.emit(UIEvents.LOGOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
},
|
},
|
||||||
"toolbar_film_strip": function () {
|
"toolbar_film_strip": function () {
|
||||||
JitsiMeetJS.analytics.sendEvent(
|
JitsiMeetJS.analytics.sendEvent(
|
||||||
|
@ -246,10 +185,6 @@ const defaultToolbarButtons = {
|
||||||
content: 'Share screen',
|
content: 'Share screen',
|
||||||
i18n: '[content]toolbar.sharescreen'
|
i18n: '[content]toolbar.sharescreen'
|
||||||
},
|
},
|
||||||
'security': {
|
|
||||||
id: 'toolbar_button_security',
|
|
||||||
tooltipKey: 'toolbar.lock'
|
|
||||||
},
|
|
||||||
'invite': {
|
'invite': {
|
||||||
id: 'toolbar_button_link',
|
id: 'toolbar_button_link',
|
||||||
tooltipKey: 'toolbar.invite',
|
tooltipKey: 'toolbar.invite',
|
||||||
|
@ -344,27 +279,28 @@ function showSipNumberInput () {
|
||||||
let defaultNumber = config.defaultSipNumber
|
let defaultNumber = config.defaultSipNumber
|
||||||
? config.defaultSipNumber
|
? config.defaultSipNumber
|
||||||
: '';
|
: '';
|
||||||
|
let titleKey = "dialog.sipMsg";
|
||||||
let sipMsg = APP.translation.generateTranslationHTML("dialog.sipMsg");
|
let sipMsg = APP.translation.generateTranslationHTML("dialog.sipMsg");
|
||||||
APP.UI.messageHandler.openTwoButtonDialog(
|
let msgString = (`
|
||||||
null, null, null,
|
<input name="sipNumber" type="text"
|
||||||
`<h2>${sipMsg}</h2>
|
value="${defaultNumber}" autofocus>
|
||||||
<input
|
`);
|
||||||
name="sipNumber"
|
|
||||||
type="text"
|
APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
value="${defaultNumber}"
|
titleKey,
|
||||||
autofocus>`,
|
titleString: sipMsg,
|
||||||
false, "dialog.Dial",
|
msgString,
|
||||||
function (e, v, m, f) {
|
leftButtonKey: "dialog.Dial",
|
||||||
|
submitFunction: function (e, v, m, f) {
|
||||||
if (v && f.sipNumber) {
|
if (v && f.sipNumber) {
|
||||||
emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
|
emitter.emit(UIEvents.SIP_DIAL, f.sipNumber);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null, null, ':input:first'
|
focus: ':input:first'
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const Toolbar = {
|
Toolbar = {
|
||||||
init (eventEmitter) {
|
init (eventEmitter) {
|
||||||
emitter = eventEmitter;
|
emitter = eventEmitter;
|
||||||
// The toolbar is enabled by default.
|
// The toolbar is enabled by default.
|
||||||
|
@ -446,41 +382,6 @@ const Toolbar = {
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
return this.enabled;
|
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
|
* Shows or hides authentication button
|
||||||
* @param show <tt>true</tt> to show or <tt>false</tt> to hide
|
* @param show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||||
|
|
|
@ -52,8 +52,10 @@ var messageHandler = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return $.prompt(message, {
|
return $.prompt(message, {
|
||||||
title: title,
|
title: this._getFormattedTitleString(title),
|
||||||
persistent: false,
|
persistent: false,
|
||||||
|
promptspeed: 0,
|
||||||
|
classes: this._getDialogClasses(),
|
||||||
close: function (e, v, m, f) {
|
close: function (e, v, m, f) {
|
||||||
if(closeFunction)
|
if(closeFunction)
|
||||||
closeFunction(e, v, m, f);
|
closeFunction(e, v, m, f);
|
||||||
|
@ -79,16 +81,31 @@ var messageHandler = {
|
||||||
* the user press 'enter'. Indexed from 0.
|
* the user press 'enter'. Indexed from 0.
|
||||||
* @return the prompt that was created, or null
|
* @return the prompt that was created, or null
|
||||||
*/
|
*/
|
||||||
openTwoButtonDialog: function(titleKey, titleString, msgKey, msgString,
|
openTwoButtonDialog: function(options) {
|
||||||
persistent, leftButtonKey, submitFunction, loadedFunction,
|
let {
|
||||||
closeFunction, focus, defaultButton) {
|
titleKey,
|
||||||
|
titleString,
|
||||||
|
msgKey,
|
||||||
|
msgString,
|
||||||
|
leftButtonKey,
|
||||||
|
submitFunction,
|
||||||
|
loadedFunction,
|
||||||
|
closeFunction,
|
||||||
|
focus,
|
||||||
|
size,
|
||||||
|
defaultButton,
|
||||||
|
wrapperClass,
|
||||||
|
classes
|
||||||
|
} = options;
|
||||||
|
|
||||||
if (!popupEnabled || twoButtonDialog)
|
if (!popupEnabled || twoButtonDialog)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var buttons = [];
|
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});
|
buttons.push({ title: leftButton, value: true});
|
||||||
|
|
||||||
var cancelButton
|
var cancelButton
|
||||||
|
@ -102,22 +119,32 @@ var messageHandler = {
|
||||||
if (msgKey) {
|
if (msgKey) {
|
||||||
message = APP.translation.generateTranslationHTML(msgKey);
|
message = APP.translation.generateTranslationHTML(msgKey);
|
||||||
}
|
}
|
||||||
|
classes = classes || this._getDialogClasses(size);
|
||||||
|
if (wrapperClass) {
|
||||||
|
classes.prompt += ` ${wrapperClass}`;
|
||||||
|
}
|
||||||
|
|
||||||
twoButtonDialog = $.prompt(message, {
|
twoButtonDialog = $.prompt(message, {
|
||||||
title: title,
|
title: this._getFormattedTitleString(title),
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
defaultButton: defaultButton,
|
defaultButton: defaultButton,
|
||||||
focus: focus,
|
focus: focus,
|
||||||
loaded: loadedFunction,
|
loaded: loadedFunction,
|
||||||
|
promptspeed: 0,
|
||||||
|
classes,
|
||||||
submit: function (e, v, m, f) {
|
submit: function (e, v, m, f) {
|
||||||
twoButtonDialog = null;
|
twoButtonDialog = null;
|
||||||
if (submitFunction)
|
if (v){
|
||||||
submitFunction(e, v, m, f);
|
if (submitFunction)
|
||||||
|
submitFunction(e, v, m, f);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
close: function (e, v, m, f) {
|
close: function (e, v, m, f) {
|
||||||
twoButtonDialog = null;
|
twoButtonDialog = null;
|
||||||
if (closeFunction)
|
if (closeFunction) {
|
||||||
closeFunction(e, v, m, f);
|
closeFunction(e, v, m, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return twoButtonDialog;
|
return twoButtonDialog;
|
||||||
|
@ -144,14 +171,16 @@ var messageHandler = {
|
||||||
if (!popupEnabled)
|
if (!popupEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var args = {
|
let args = {
|
||||||
title: titleString,
|
title: this._getFormattedTitleString(titleString),
|
||||||
persistent: persistent,
|
persistent: persistent,
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
|
promptspeed: 0,
|
||||||
loaded: loadedFunction,
|
loaded: loadedFunction,
|
||||||
submit: submitFunction,
|
submit: submitFunction,
|
||||||
close: closeFunction
|
close: closeFunction,
|
||||||
|
classes: this._getDialogClasses()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (persistent) {
|
if (persistent) {
|
||||||
|
@ -161,6 +190,40 @@ var messageHandler = {
|
||||||
return new Impromptu(msgString, args);
|
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.
|
* Closes currently opened dialog.
|
||||||
*/
|
*/
|
||||||
|
@ -176,7 +239,18 @@ var messageHandler = {
|
||||||
openDialogWithStates: function (statesObject, options) {
|
openDialogWithStates: function (statesObject, options) {
|
||||||
if (!popupEnabled)
|
if (!popupEnabled)
|
||||||
return;
|
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);
|
return new Impromptu(statesObject, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -210,6 +284,7 @@ var messageHandler = {
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
return popup;
|
return popup;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -172,19 +172,23 @@ var KeyboardShortcut = {
|
||||||
*/
|
*/
|
||||||
_addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
|
_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;
|
listElement.id = shortcutChar;
|
||||||
|
|
||||||
var spanElement = document.createElement("span");
|
let spanElement = document.createElement("span");
|
||||||
spanElement.className = "item-action";
|
spanElement.className = "item-action";
|
||||||
|
|
||||||
var kbdElement = document.createElement("kbd");
|
let kbdElement = document.createElement("kbd");
|
||||||
kbdElement.className = "regular-key";
|
let classes = 'aui-label regular-key';
|
||||||
|
kbdElement.className = classes;
|
||||||
kbdElement.innerHTML = shortcutChar;
|
kbdElement.innerHTML = shortcutChar;
|
||||||
spanElement.appendChild(kbdElement);
|
spanElement.appendChild(kbdElement);
|
||||||
|
|
||||||
var descriptionElement = document.createElement("span");
|
let descriptionElement = document.createElement("span");
|
||||||
descriptionElement.className = "item-description";
|
let descriptionClass = "shortcuts-list__description";
|
||||||
|
descriptionElement.className = descriptionClass;
|
||||||
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
|
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
|
||||||
descriptionElement.innerHTML
|
descriptionElement.innerHTML
|
||||||
= APP.translation.translateString(shortcutDescriptionKey);
|
= APP.translation.translateString(shortcutDescriptionKey);
|
||||||
|
@ -192,7 +196,7 @@ var KeyboardShortcut = {
|
||||||
listElement.appendChild(spanElement);
|
listElement.appendChild(spanElement);
|
||||||
listElement.appendChild(descriptionElement);
|
listElement.appendChild(descriptionElement);
|
||||||
|
|
||||||
var parentListElement
|
let parentListElement
|
||||||
= document.getElementById("keyboard-shortcuts-list");
|
= document.getElementById("keyboard-shortcuts-list");
|
||||||
|
|
||||||
if (parentListElement)
|
if (parentListElement)
|
||||||
|
|
|
@ -22,13 +22,16 @@ export default {
|
||||||
VIDEO_MUTED: "UI.video_muted",
|
VIDEO_MUTED: "UI.video_muted",
|
||||||
ETHERPAD_CLICKED: "UI.etherpad_clicked",
|
ETHERPAD_CLICKED: "UI.etherpad_clicked",
|
||||||
SHARED_VIDEO_CLICKED: "UI.start_shared_video",
|
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)
|
* Updates shared video with params: url, state, time(optional)
|
||||||
* Where url is the video link, state is stop/start/pause and time is the
|
* Where url is the video link, state is stop/start/pause and time is the
|
||||||
* current video playing time.
|
* current video playing time.
|
||||||
*/
|
*/
|
||||||
UPDATE_SHARED_VIDEO: "UI.update_shared_video",
|
UPDATE_SHARED_VIDEO: "UI.update_shared_video",
|
||||||
ROOM_LOCK_CLICKED: "UI.room_lock_clicked",
|
|
||||||
USER_KICKED: "UI.user_kicked",
|
USER_KICKED: "UI.user_kicked",
|
||||||
REMOTE_AUDIO_MUTED: "UI.remote_audio_muted",
|
REMOTE_AUDIO_MUTED: "UI.remote_audio_muted",
|
||||||
FULLSCREEN_TOGGLE: "UI.fullscreen_toggle",
|
FULLSCREEN_TOGGLE: "UI.fullscreen_toggle",
|
||||||
|
@ -114,5 +117,40 @@ export default {
|
||||||
/**
|
/**
|
||||||
* Notifies that the avatar is displayed or not on the largeVideo.
|
* 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