mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-30 20:57:46 +00:00
Compare commits
145 Commits
1470
...
move_loggi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf83b4142a | ||
|
|
75b3bc6190 | ||
|
|
6c716bcbb1 | ||
|
|
44beed6216 | ||
|
|
2352811c20 | ||
|
|
c1df375af4 | ||
|
|
e8c631de01 | ||
|
|
bdc67201e2 | ||
|
|
0db33bb45c | ||
|
|
9f26270a98 | ||
|
|
df721cbd2e | ||
|
|
8745efb81f | ||
|
|
e56f1a9ded | ||
|
|
52fbb8f02c | ||
|
|
a1639b67a5 | ||
|
|
3475ad4674 | ||
|
|
685d117a91 | ||
|
|
e51f791ab0 | ||
|
|
0f2ba1cefe | ||
|
|
1f457dfca5 | ||
|
|
841050953f | ||
|
|
c6296821c0 | ||
|
|
7c8ca45d9a | ||
|
|
142f6e4518 | ||
|
|
f72e7ffbc2 | ||
|
|
111b6e1c27 | ||
|
|
4add2d0590 | ||
|
|
cb0f7417b6 | ||
|
|
06eb7c6109 | ||
|
|
4d0701cfda | ||
|
|
86bce1e5f6 | ||
|
|
8da0d3a1f1 | ||
|
|
f32438b219 | ||
|
|
0238a10a4b | ||
|
|
6669a96fd8 | ||
|
|
09406bfbfc | ||
|
|
51da40e90c | ||
|
|
52847bd28d | ||
|
|
835d3c6a25 | ||
|
|
00e6e98a61 | ||
|
|
6d90adcdf6 | ||
|
|
06d2fb0aca | ||
|
|
c3428e8213 | ||
|
|
57b0736ebb | ||
|
|
6211566c0c | ||
|
|
48bb427f71 | ||
|
|
56f15356c7 | ||
|
|
8e6fd0ca95 | ||
|
|
b5dfc2a520 | ||
|
|
4900fe020d | ||
|
|
94bd6bc330 | ||
|
|
36bcc6831b | ||
|
|
76c89845a8 | ||
|
|
b58f1cdd16 | ||
|
|
141c64cd00 | ||
|
|
51b802da84 | ||
|
|
71c27f308c | ||
|
|
75b9adf01b | ||
|
|
a079914603 | ||
|
|
4d3ca4a85a | ||
|
|
afa1d5423c | ||
|
|
766eb94c7d | ||
|
|
ad6e793615 | ||
|
|
d900d3c3fd | ||
|
|
7f315ef105 | ||
|
|
dc0a7e7628 | ||
|
|
6d1f42bf30 | ||
|
|
c26b144f0d | ||
|
|
752f4dd5de | ||
|
|
693ebbea9d | ||
|
|
b24a54aab2 | ||
|
|
00aee89709 | ||
|
|
a5f243e18d | ||
|
|
d05ff9b4ee | ||
|
|
a67087b6de | ||
|
|
e2ea16ea3f | ||
|
|
5098b64666 | ||
|
|
66fbc28385 | ||
|
|
4bcd75f15c | ||
|
|
da6af88910 | ||
|
|
1a91f4953b | ||
|
|
9a0d28720d | ||
|
|
5b6956e25b | ||
|
|
fd51108ae3 | ||
|
|
73a2eca51c | ||
|
|
9bc24e1caa | ||
|
|
3fc02bf6c2 | ||
|
|
3bd4f1d5d8 | ||
|
|
f3dbeea091 | ||
|
|
d2ef94a7eb | ||
|
|
1d1d8defda | ||
|
|
d0127b879d | ||
|
|
cbc6943305 | ||
|
|
9124aa2c87 | ||
|
|
8817f0c53d | ||
|
|
e4f9c17f8a | ||
|
|
686ee1111a | ||
|
|
4b11767ac5 | ||
|
|
5545c0d905 | ||
|
|
611edf7e34 | ||
|
|
7a37d70fb6 | ||
|
|
b2577090bd | ||
|
|
5b0777d4db | ||
|
|
12c1574f07 | ||
|
|
5623a06996 | ||
|
|
148960c6d2 | ||
|
|
ff8c6690ef | ||
|
|
c926e95822 | ||
|
|
0a28dd0cd3 | ||
|
|
8caae4bfde | ||
|
|
a67c5a8dc7 | ||
|
|
cf38fde207 | ||
|
|
4549b766f5 | ||
|
|
45126d4f3d | ||
|
|
82926ef8c6 | ||
|
|
42604971dc | ||
|
|
95fcf5bae5 | ||
|
|
34acadc3b5 | ||
|
|
d3df082e3d | ||
|
|
fe7e9f333f | ||
|
|
92901e09e1 | ||
|
|
128b301a39 | ||
|
|
1b1b9475a4 | ||
|
|
5aff96e3b7 | ||
|
|
fb4e9b3c6d | ||
|
|
a8a6b38c28 | ||
|
|
68ab87cc0d | ||
|
|
986c29ca5d | ||
|
|
d7fc20b607 | ||
|
|
96b280668d | ||
|
|
66b7404961 | ||
|
|
7f3323f7c0 | ||
|
|
e34d86b485 | ||
|
|
34ea330aa3 | ||
|
|
70c3c1a21c | ||
|
|
98d3755859 | ||
|
|
a4a1579c84 | ||
|
|
20c6dba599 | ||
|
|
f09a9be523 | ||
|
|
91340a5268 | ||
|
|
c41c219206 | ||
|
|
16a2b0377a | ||
|
|
b1f129a53a | ||
|
|
a6a7e81a0f | ||
|
|
d60146c6a8 |
@@ -8,3 +8,6 @@ indent_size = 4
|
||||
indent_style = space
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
build/
|
||||
debian/
|
||||
libs/
|
||||
node_modules/
|
||||
|
||||
2
404.html
2
404.html
@@ -6,7 +6,7 @@
|
||||
<body>
|
||||
<div class="error_page">
|
||||
<h2>404 Not Found</h2>
|
||||
<p class="error_page__message">You can create new conversation <a href="/">here</a></p>
|
||||
<p class="error_page__message">You can create new conversation <a class="link" href="/">here</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -27,5 +27,7 @@
|
||||
action + '.' + data.browserName, label, value);
|
||||
};
|
||||
|
||||
ctx.Analytics = Analytics;
|
||||
if(typeof ctx.analyticsHandlers === "undefined")
|
||||
ctx.analyticsHandlers = [];
|
||||
ctx.analyticsHandlers.push(Analytics);
|
||||
}(window));
|
||||
|
||||
124
app.js
124
app.js
@@ -1,5 +1,6 @@
|
||||
/* global $, config, getRoomName */
|
||||
/* global $, config, getRoomName, loggingConfig, JitsiMeetJS */
|
||||
/* application specific logic */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import "babel-polyfill";
|
||||
import "jquery";
|
||||
@@ -18,6 +19,10 @@ import 'aui-experimental-css';
|
||||
|
||||
window.toastr = require("toastr");
|
||||
|
||||
const Logger = require("jitsi-meet-logger");
|
||||
const LogCollector = Logger.LogCollector;
|
||||
import JitsiMeetLogStorage from "./modules/util/JitsiMeetLogStorage";
|
||||
|
||||
import URLProcessor from "./modules/config/URLProcessor";
|
||||
import RoomnameGenerator from './modules/util/RoomnameGenerator';
|
||||
|
||||
@@ -31,6 +36,8 @@ import UIEvents from './service/UI/UIEvents';
|
||||
import getTokenData from "./modules/tokendata/TokenData";
|
||||
import translation from "./modules/translation/translation";
|
||||
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
/**
|
||||
* Tries to push history state with the following parameters:
|
||||
* 'VideoChat', `Room: ${roomName}`, URL. If fail, prints the error and returns
|
||||
@@ -42,7 +49,7 @@ function pushHistoryState(roomName, URL) {
|
||||
'VideoChat', `Room: ${roomName}`, URL
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn("Push history state failed with parameters:",
|
||||
logger.warn("Push history state failed with parameters:",
|
||||
'VideoChat', `Room: ${roomName}`, URL, e);
|
||||
return e;
|
||||
}
|
||||
@@ -78,6 +85,36 @@ function buildRoomName () {
|
||||
return roomName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the logging levels.
|
||||
* @private
|
||||
*/
|
||||
function configureLoggingLevels () {
|
||||
// NOTE The library Logger is separated from the app loggers, so the levels
|
||||
// have to be set in two places
|
||||
|
||||
// Set default logging level
|
||||
const defaultLogLevel
|
||||
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
|
||||
Logger.setLogLevel(defaultLogLevel);
|
||||
JitsiMeetJS.setLogLevel(defaultLogLevel);
|
||||
|
||||
// NOTE console was used on purpose here to go around the logging
|
||||
// and always print the default logging level to the console
|
||||
console.info("Default logging level set to: " + defaultLogLevel);
|
||||
|
||||
// Set log level for each logger
|
||||
if (loggingConfig) {
|
||||
Object.keys(loggingConfig).forEach(function(loggerName) {
|
||||
if ('defaultLogLevel' !== loggerName) {
|
||||
const level = loggingConfig[loggerName];
|
||||
Logger.setLogLevelById(level, loggerName);
|
||||
JitsiMeetJS.setLogLevelById(level, loggerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const APP = {
|
||||
// Used by do_external_connect.js if we receive the attach data after
|
||||
// connect was already executed. status property can be "initialized",
|
||||
@@ -97,6 +134,16 @@ const APP = {
|
||||
settings,
|
||||
conference,
|
||||
translation,
|
||||
/**
|
||||
* The log collector which captures JS console logs for this app.
|
||||
* @type {LogCollector}
|
||||
*/
|
||||
logCollector: null,
|
||||
/**
|
||||
* Indicates if the log collector has been started (it will not be started
|
||||
* if the welcome page is displayed).
|
||||
*/
|
||||
logCollectorStarted : false,
|
||||
/**
|
||||
* After the APP has been initialized provides utility methods for dealing
|
||||
* with the conference room URL(address).
|
||||
@@ -106,10 +153,24 @@ const APP = {
|
||||
connection: null,
|
||||
API,
|
||||
init () {
|
||||
this.initLogging();
|
||||
this.keyboardshortcut =
|
||||
require("./modules/keyboardshortcut/keyboardshortcut");
|
||||
this.configFetch = require("./modules/config/HttpConfigFetch");
|
||||
this.tokenData = getTokenData();
|
||||
},
|
||||
initLogging () {
|
||||
// Adjust logging level
|
||||
configureLoggingLevels();
|
||||
// Create the LogCollector and register it as the global log transport.
|
||||
// It is done early to capture as much logs as possible. Captured logs
|
||||
// will be cached, before the JitsiMeetLogStorage gets ready (statistics
|
||||
// module is initialized).
|
||||
if (!this.logCollector && !loggingConfig.disableLogCollector) {
|
||||
this.logCollector = new LogCollector(new JitsiMeetLogStorage());
|
||||
Logger.addGlobalTransport(this.logCollector);
|
||||
JitsiMeetJS.addGlobalLogTransport(this.logCollector);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,21 +192,60 @@ function init() {
|
||||
APP.ConferenceUrl = new ConferenceUrl(window.location);
|
||||
// Clean up the URL displayed by the browser
|
||||
replaceHistoryState(APP.ConferenceUrl.getInviteUrl());
|
||||
var isUIReady = APP.UI.start();
|
||||
|
||||
// TODO The execution of the mobile app starts from react/index.native.js.
|
||||
// Similarly, the execution of the Web app should start from
|
||||
// react/index.web.js for the sake of consistency and ease of understanding.
|
||||
// Temporarily though because we are at the beginning of introducing React
|
||||
// into the Web app, allow the execution of the Web app to start from app.js
|
||||
// in order to reduce the complexity of the beginning step.
|
||||
require('./react');
|
||||
|
||||
const isUIReady = APP.UI.start();
|
||||
if (isUIReady) {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(function () {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(() => {
|
||||
|
||||
if (APP.logCollector) {
|
||||
// Start the LogCollector's periodic "store logs" task only if
|
||||
// we're in the conference and not on the welcome page. This is
|
||||
// determined by the value of "isUIReady" const above.
|
||||
APP.logCollector.start();
|
||||
APP.logCollectorStarted = true;
|
||||
// Make an attempt to flush in case a lot of logs have been
|
||||
// cached, before the collector was started.
|
||||
APP.logCollector.flush();
|
||||
|
||||
// This event listener will flush the logs, before
|
||||
// the statistics module (CallStats) is stopped.
|
||||
//
|
||||
// NOTE The LogCollector is not stopped, because this event can
|
||||
// be triggered multiple times during single conference
|
||||
// (whenever statistics module is stopped). That includes
|
||||
// the case when Jicofo terminates the single person left in the
|
||||
// room. It will then restart the media session when someone
|
||||
// eventually join the room which will start the stats again.
|
||||
APP.conference.addConferenceListener(
|
||||
ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
|
||||
() => {
|
||||
if (APP.logCollector) {
|
||||
APP.logCollector.flush();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, function (language) {
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
|
||||
APP.translation.setLanguage(language);
|
||||
APP.settings.setLanguage(language);
|
||||
});
|
||||
|
||||
APP.keyboardshortcut.init();
|
||||
}).catch(function (err) {
|
||||
}).catch(err => {
|
||||
APP.UI.hideRingOverLay();
|
||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||
console.error(err);
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -169,7 +269,7 @@ function obtainConfigAndInit() {
|
||||
if (success) {
|
||||
var now = APP.connectionTimes["configuration.fetched"] =
|
||||
window.performance.now();
|
||||
console.log("(TIME) configuration fetched:\t", now);
|
||||
logger.log("(TIME) configuration fetched:\t", now);
|
||||
init();
|
||||
} else {
|
||||
// Show obtain config error,
|
||||
@@ -189,9 +289,10 @@ function obtainConfigAndInit() {
|
||||
|
||||
$(document).ready(function () {
|
||||
var now = APP.connectionTimes["document.ready"] = window.performance.now();
|
||||
console.log("(TIME) document ready:\t", now);
|
||||
logger.log("(TIME) document ready:\t", now);
|
||||
|
||||
URLProcessor.setConfigParametersFromUrl();
|
||||
|
||||
APP.init();
|
||||
|
||||
APP.translation.init(settings.getLanguage());
|
||||
@@ -202,6 +303,11 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
$(window).bind('beforeunload', function () {
|
||||
// Stop the LogCollector
|
||||
if (APP.logCollectorStarted) {
|
||||
APP.logCollector.stop();
|
||||
APP.logCollectorStarted = false;
|
||||
}
|
||||
APP.API.dispose();
|
||||
});
|
||||
|
||||
|
||||
15
close.html
15
close.html
@@ -3,21 +3,12 @@
|
||||
<link rel="stylesheet" href="css/all.css"/>
|
||||
<!--#include virtual="title.html" -->
|
||||
<script><!--#include virtual="/interface_config.js" --></script>
|
||||
<script>function translateStr(id, msg) {
|
||||
var div = document.getElementById(id);
|
||||
div.innerHTML = msg;
|
||||
}
|
||||
function translate() {
|
||||
translateStr('hintMessage',
|
||||
'You can use video calls with '
|
||||
+ interfaceConfig.APP_NAME +' for your business');
|
||||
}
|
||||
</script>
|
||||
<script src="close.js"></script>
|
||||
</head>
|
||||
<body onload="translate();">
|
||||
<body>
|
||||
<div class="redirectPageMessage">
|
||||
<div class="thanks-msg">
|
||||
<p id="thanksMessage">Thank you for your feedback!</p>
|
||||
<p>Thank you for your feedback!</p>
|
||||
</div>
|
||||
<div class="hint-msg">
|
||||
<p>
|
||||
|
||||
48
close.js
Normal file
48
close.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/* global interfaceConfig */
|
||||
//list of tips
|
||||
var hints = [
|
||||
"You can pin participants by clicking on their thumbnails.",// jshint ignore:line
|
||||
"You can tell others you have something to say by using the \"Raise Hand\" feature",// jshint ignore:line
|
||||
"You can learn about key shortcuts by pressing Shift+?",// jshint ignore:line
|
||||
"You can learn more about the state of everyone's connection by hovering on the bars in their thumbnail",// jshint ignore:line
|
||||
"You can hide all thumbnails by using the button in the bottom right corner"// jshint ignore:line
|
||||
];
|
||||
|
||||
/**
|
||||
* Get a random hint meessage from hint array.
|
||||
*
|
||||
* @return {string} the hint message.
|
||||
*/
|
||||
function getHint(){
|
||||
var l = hints.length - 1;
|
||||
var n = Math.round(Math.random() * l);
|
||||
|
||||
return hints[n];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts text message
|
||||
* into DOM element
|
||||
*
|
||||
* @param id {string} element identificator
|
||||
* @param msg {string} text message
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function insertTextMsg(id, msg){
|
||||
var el = document.getElementById(id);
|
||||
|
||||
if (el)
|
||||
el.innerText = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hint and thanks messages. Will be executed on load event.
|
||||
*/
|
||||
function onLoad() {
|
||||
//Works only for close2.html because close.html doesn't have this element.
|
||||
insertTextMsg('thanksMessage',
|
||||
'Thank you for using ' + interfaceConfig.APP_NAME);
|
||||
insertTextMsg('hintMessage', getHint());
|
||||
}
|
||||
|
||||
window.onload = onLoad;
|
||||
15
close2.html
15
close2.html
@@ -3,20 +3,9 @@
|
||||
<link rel="stylesheet" href="css/all.css"/>
|
||||
<!--#include virtual="title.html" -->
|
||||
<script><!--#include virtual="/interface_config.js" --></script>
|
||||
<script>function translateStr(id, msg) {
|
||||
var div = document.getElementById(id);
|
||||
div.innerHTML = msg;
|
||||
}
|
||||
function translate() {
|
||||
translateStr('thanksMessage',
|
||||
'Thank you for using ' + interfaceConfig.APP_NAME);
|
||||
translateStr('hintMessage',
|
||||
'You can use video calls with '
|
||||
+ interfaceConfig.APP_NAME +' for your business');
|
||||
}
|
||||
</script>
|
||||
<script src="close.js"></script>
|
||||
</head>
|
||||
<body onload="translate();">
|
||||
<body>
|
||||
<div class="redirectPageMessage">
|
||||
<div class="thanks-msg">
|
||||
<p id="thanksMessage"></p>
|
||||
|
||||
196
conference.js
196
conference.js
@@ -1,4 +1,6 @@
|
||||
/* global $, APP, JitsiMeetJS, config, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import {openConnection} from './connection';
|
||||
import Invite from './modules/UI/invite/Invite';
|
||||
import ContactList from './modules/UI/side_pannels/contactlist/ContactList';
|
||||
@@ -13,6 +15,8 @@ import {reportError} from './modules/util/helpers';
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
import UIUtil from './modules/UI/util/UIUtil';
|
||||
|
||||
import analytics from './modules/analytics/analytics';
|
||||
|
||||
const ConnectionEvents = JitsiMeetJS.events.connection;
|
||||
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
||||
|
||||
@@ -45,6 +49,12 @@ const commands = {
|
||||
CUSTOM_ROLE: "custom-role"
|
||||
};
|
||||
|
||||
/**
|
||||
* Max length of the display names. If we receive longer display name the
|
||||
* additional chars are going to be cut.
|
||||
*/
|
||||
const MAX_DISPLAY_NAME_LENGTH = 50;
|
||||
|
||||
/**
|
||||
* Open Connection. When authentication failed it shows auth dialog.
|
||||
* @param roomName the room name to use
|
||||
@@ -158,7 +168,7 @@ function muteLocalMedia(localMedia, muted, localMediaTypeString) {
|
||||
const method = muted ? 'mute' : 'unmute';
|
||||
|
||||
localMedia[method]().catch(reason => {
|
||||
console.warn(`${localMediaTypeString} ${method} was rejected:`, reason);
|
||||
logger.warn(`${localMediaTypeString} ${method} was rejected:`, reason);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -246,7 +256,7 @@ function createLocalTracks (options, checkForPermissionPrompt) {
|
||||
});
|
||||
return tracks;
|
||||
}).catch(function (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
'failed to create local tracks', options.devices, err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
@@ -273,21 +283,23 @@ function changeLocalEmail(email = '') {
|
||||
* @param nickname {string} the new display name
|
||||
*/
|
||||
function changeLocalDisplayName(nickname = '') {
|
||||
nickname = nickname.trim();
|
||||
const formattedNickname
|
||||
= nickname.trim().substr(0, MAX_DISPLAY_NAME_LENGTH);
|
||||
|
||||
if (nickname === APP.settings.getDisplayName()) {
|
||||
if (formattedNickname === APP.settings.getDisplayName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
APP.settings.setDisplayName(nickname);
|
||||
room.setDisplayName(nickname);
|
||||
APP.UI.changeDisplayName(APP.conference.getMyUserId(), nickname);
|
||||
APP.settings.setDisplayName(formattedNickname);
|
||||
room.setDisplayName(formattedNickname);
|
||||
APP.UI.changeDisplayName(APP.conference.getMyUserId(), formattedNickname);
|
||||
}
|
||||
|
||||
class ConferenceConnector {
|
||||
constructor(resolve, reject) {
|
||||
constructor(resolve, reject, invite) {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
this._invite = invite;
|
||||
this.reconnectTimeout = null;
|
||||
room.on(ConferenceEvents.CONFERENCE_JOINED,
|
||||
this._handleConferenceJoined.bind(this));
|
||||
@@ -301,7 +313,7 @@ class ConferenceConnector {
|
||||
this._reject(err);
|
||||
}
|
||||
_onConferenceFailed(err, ...params) {
|
||||
console.error('CONFERENCE FAILED:', err, ...params);
|
||||
logger.error('CONFERENCE FAILED:', err, ...params);
|
||||
APP.UI.hideRingOverLay();
|
||||
switch (err) {
|
||||
// room is locked by the password
|
||||
@@ -331,7 +343,8 @@ class ConferenceConnector {
|
||||
}, 5000);
|
||||
|
||||
// notify user that auth is required
|
||||
AuthHandler.requireAuth(room, this.invite.getRoomLocker().password);
|
||||
AuthHandler.requireAuth(
|
||||
room, this._invite.getRoomLocker().password);
|
||||
break;
|
||||
|
||||
case ConferenceErrors.RESERVATION_ERROR:
|
||||
@@ -374,7 +387,8 @@ class ConferenceConnector {
|
||||
// the app. Both the errors above are unrecoverable from the library
|
||||
// perspective.
|
||||
room.leave().then(() => connection.disconnect());
|
||||
APP.UI.showPageReloadOverlay();
|
||||
APP.UI.showPageReloadOverlay(
|
||||
false /* not a network type of failure */, err);
|
||||
break;
|
||||
|
||||
case ConferenceErrors.CONFERENCE_MAX_USERS:
|
||||
@@ -389,7 +403,7 @@ class ConferenceConnector {
|
||||
}
|
||||
}
|
||||
_onConferenceError(err, ...params) {
|
||||
console.error('CONFERENCE Error:', err, params);
|
||||
logger.error('CONFERENCE Error:', err, params);
|
||||
switch (err) {
|
||||
case ConferenceErrors.CHAT_ERROR:
|
||||
{
|
||||
@@ -398,7 +412,7 @@ class ConferenceConnector {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown error.");
|
||||
logger.error("Unknown error.", err);
|
||||
}
|
||||
}
|
||||
_unsubscribe() {
|
||||
@@ -431,26 +445,6 @@ function disconnect() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permanent properties to analytics.
|
||||
* NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
|
||||
* null.
|
||||
*/
|
||||
function setAnalyticsPermanentProperties() {
|
||||
let permanentProperties = {
|
||||
userAgent: navigator.userAgent,
|
||||
roomName: APP.conference.roomName
|
||||
};
|
||||
let {server, group} = APP.tokenData;
|
||||
if(server) {
|
||||
permanentProperties.server = server;
|
||||
}
|
||||
if(group) {
|
||||
permanentProperties.group = group;
|
||||
}
|
||||
JitsiMeetJS.analytics.addPermanentProperties(permanentProperties);
|
||||
}
|
||||
|
||||
export default {
|
||||
isModerator: false,
|
||||
audioMuted: false,
|
||||
@@ -473,8 +467,6 @@ export default {
|
||||
*/
|
||||
init(options) {
|
||||
this.roomName = options.roomName;
|
||||
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.TRACE);
|
||||
|
||||
// attaches global error handler, if there is already one, respect it
|
||||
if(JitsiMeetJS.getGlobalOnErrorHandler){
|
||||
var oldOnErrorHandler = window.onerror;
|
||||
@@ -497,12 +489,14 @@ export default {
|
||||
};
|
||||
}
|
||||
|
||||
return JitsiMeetJS.init(config)
|
||||
.then(() => {
|
||||
setAnalyticsPermanentProperties();
|
||||
return JitsiMeetJS.init(
|
||||
Object.assign(
|
||||
{enableAnalyticsLogging: analytics.isEnabled()}, config)
|
||||
).then(() => {
|
||||
analytics.init();
|
||||
return createInitialLocalTracksAndConnect(options.roomName);
|
||||
}).then(([tracks, con]) => {
|
||||
console.log('initialized with %s local tracks', tracks.length);
|
||||
logger.log('initialized with %s local tracks', tracks.length);
|
||||
APP.connection = connection = con;
|
||||
this._bindConnectionFailedHandler(con);
|
||||
this._createRoom(tracks);
|
||||
@@ -530,7 +524,8 @@ export default {
|
||||
// XXX The API will take care of disconnecting from the XMPP
|
||||
// server (and, thus, leaving the room) on unload.
|
||||
return new Promise((resolve, reject) => {
|
||||
(new ConferenceConnector(resolve, reject)).connect();
|
||||
(new ConferenceConnector(
|
||||
resolve, reject, this.invite)).connect();
|
||||
});
|
||||
});
|
||||
},
|
||||
@@ -551,15 +546,34 @@ export default {
|
||||
*/
|
||||
_bindConnectionFailedHandler (connection) {
|
||||
const handler = function (error, errMsg) {
|
||||
if (ConnectionErrors.OTHER_ERROR === error) {
|
||||
// - item-not-found
|
||||
// - connection dropped(closed by Strophe unexpectedly
|
||||
// possible due too many transport errors)
|
||||
console.error("XMPP connection error: " + errMsg);
|
||||
APP.UI.showPageReloadOverlay();
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED, handler);
|
||||
/* eslint-disable no-case-declarations */
|
||||
switch (error) {
|
||||
case ConnectionErrors.CONNECTION_DROPPED_ERROR:
|
||||
case ConnectionErrors.OTHER_ERROR:
|
||||
case ConnectionErrors.SERVER_ERROR:
|
||||
|
||||
logger.error("XMPP connection error: " + errMsg);
|
||||
|
||||
// From all of the cases above only CONNECTION_DROPPED_ERROR
|
||||
// is considered a network type of failure
|
||||
const isNetworkFailure
|
||||
= error === ConnectionErrors.CONNECTION_DROPPED_ERROR;
|
||||
|
||||
APP.UI.showPageReloadOverlay(
|
||||
isNetworkFailure,
|
||||
"xmpp-conn-dropped:" + errMsg);
|
||||
|
||||
connection.removeEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED, handler);
|
||||
|
||||
// FIXME it feels like the conference should be stopped
|
||||
// by lib-jitsi-meet
|
||||
if (room)
|
||||
room.leave();
|
||||
|
||||
break;
|
||||
}
|
||||
/* eslint-enable no-case-declarations */
|
||||
};
|
||||
connection.addEventListener(
|
||||
ConnectionEvents.CONNECTION_FAILED, handler);
|
||||
@@ -881,7 +895,7 @@ export default {
|
||||
} else if (track.isVideoTrack()) {
|
||||
return this.useVideoStream(track);
|
||||
} else {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Ignored not an audio nor a video track: ", track);
|
||||
return Promise.resolve();
|
||||
}
|
||||
@@ -973,11 +987,11 @@ export default {
|
||||
videoSwitchInProgress: false,
|
||||
toggleScreenSharing (shareScreen = !this.isSharingScreen) {
|
||||
if (this.videoSwitchInProgress) {
|
||||
console.warn("Switch in progress.");
|
||||
logger.warn("Switch in progress.");
|
||||
return;
|
||||
}
|
||||
if (!this.isDesktopSharingEnabled) {
|
||||
console.warn("Cannot toggle screen sharing: not supported.");
|
||||
logger.warn("Cannot toggle screen sharing: not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1031,7 +1045,7 @@ export default {
|
||||
this.videoSwitchInProgress = false;
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
'conference.sharingDesktop.start');
|
||||
console.log('sharing local desktop');
|
||||
logger.log('sharing local desktop');
|
||||
}).catch((err) => {
|
||||
// close external installation dialog to show the error.
|
||||
if(externalInstallation)
|
||||
@@ -1043,7 +1057,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error('failed to share local desktop', err);
|
||||
logger.error('failed to share local desktop', err);
|
||||
|
||||
if (err.name === TrackErrors.FIREFOX_EXTENSION_NEEDED) {
|
||||
APP.UI.showExtensionRequiredDialog(
|
||||
@@ -1080,11 +1094,11 @@ export default {
|
||||
this.videoSwitchInProgress = false;
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
'conference.sharingDesktop.stop');
|
||||
console.log('sharing local video');
|
||||
logger.log('sharing local video');
|
||||
}).catch((err) => {
|
||||
this.useVideoStream(null);
|
||||
this.videoSwitchInProgress = false;
|
||||
console.error('failed to share local video', err);
|
||||
logger.error('failed to share local video', err);
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -1110,7 +1124,7 @@ export default {
|
||||
if (user.isHidden())
|
||||
return;
|
||||
|
||||
console.log('USER %s connnected', id, user);
|
||||
logger.log('USER %s connnected', id, user);
|
||||
APP.API.notifyUserJoined(id);
|
||||
APP.UI.addUser(user);
|
||||
|
||||
@@ -1118,7 +1132,7 @@ export default {
|
||||
APP.UI.updateUserRole(user);
|
||||
});
|
||||
room.on(ConferenceEvents.USER_LEFT, (id, user) => {
|
||||
console.log('USER %s LEFT', id, user);
|
||||
logger.log('USER %s LEFT', id, user);
|
||||
APP.API.notifyUserLeft(id);
|
||||
APP.UI.removeUser(id, user.getDisplayName());
|
||||
APP.UI.onSharedVideoStop(id);
|
||||
@@ -1127,7 +1141,7 @@ export default {
|
||||
|
||||
room.on(ConferenceEvents.USER_ROLE_CHANGED, (id, role) => {
|
||||
if (this.isLocalId(id)) {
|
||||
console.info(`My role changed, new role: ${role}`);
|
||||
logger.info(`My role changed, new role: ${role}`);
|
||||
if (this.isModerator !== room.isModerator()) {
|
||||
this.isModerator = room.isModerator();
|
||||
APP.UI.updateLocalRole(room.isModerator());
|
||||
@@ -1185,7 +1199,7 @@ export default {
|
||||
{
|
||||
this.audioLevelsMap[id] = lvl;
|
||||
if(config.debugAudioLevels)
|
||||
console.log("AudioLevel:" + id + "/" + lvl);
|
||||
logger.log("AudioLevel:" + id + "/" + lvl);
|
||||
}
|
||||
|
||||
APP.UI.setAudioLevel(id, lvl);
|
||||
@@ -1252,8 +1266,10 @@ export default {
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.DISPLAY_NAME_CHANGED, (id, displayName) => {
|
||||
APP.API.notifyDisplayNameChanged(id, displayName);
|
||||
APP.UI.changeDisplayName(id, displayName);
|
||||
const formattedDisplayName
|
||||
= displayName.substr(0, MAX_DISPLAY_NAME_LENGTH);
|
||||
APP.API.notifyDisplayNameChanged(id, formattedDisplayName);
|
||||
APP.UI.changeDisplayName(id, formattedDisplayName);
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,
|
||||
@@ -1264,7 +1280,7 @@ export default {
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.RECORDER_STATE_CHANGED, (status, error) => {
|
||||
console.log("Received recorder status change: ", status, error);
|
||||
logger.log("Received recorder status change: ", status, error);
|
||||
APP.UI.updateRecordingState(status);
|
||||
});
|
||||
|
||||
@@ -1274,6 +1290,30 @@ export default {
|
||||
// FIXME close
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.SUSPEND_DETECTED, () => {
|
||||
// After wake up, we will be in a state where conference is left
|
||||
// there will be dialog shown to user.
|
||||
// We do not want video/audio as we show an overlay and after it
|
||||
// user need to rejoin or close, while waking up we can detect
|
||||
// camera wakeup as a problem with device.
|
||||
// We also do not care about device change, which happens
|
||||
// on resume after suspending PC.
|
||||
if (this.deviceChangeListener)
|
||||
JitsiMeetJS.mediaDevices.removeEventListener(
|
||||
JitsiMeetJS.events.mediaDevices.DEVICE_LIST_CHANGED,
|
||||
this.deviceChangeListener);
|
||||
|
||||
// stop local video
|
||||
if (localVideo)
|
||||
localVideo.dispose();
|
||||
// stop local audio
|
||||
if (localAudio)
|
||||
localAudio.dispose();
|
||||
|
||||
// show overlay
|
||||
APP.UI.showSuspendedOverlay();
|
||||
});
|
||||
|
||||
room.on(ConferenceEvents.DTMF_SUPPORT_CHANGED, (isDTMFSupported) => {
|
||||
APP.UI.updateDTMFSupport(isDTMFSupported);
|
||||
});
|
||||
@@ -1476,7 +1516,7 @@ export default {
|
||||
})
|
||||
.then(([stream]) => {
|
||||
this.useVideoStream(stream);
|
||||
console.log('switched local video device');
|
||||
logger.log('switched local video device');
|
||||
APP.settings.setCameraDeviceId(cameraDeviceId, true);
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -1498,7 +1538,7 @@ export default {
|
||||
})
|
||||
.then(([stream]) => {
|
||||
this.useAudioStream(stream);
|
||||
console.log('switched local audio device');
|
||||
logger.log('switched local audio device');
|
||||
APP.settings.setMicDeviceId(micDeviceId, true);
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -1514,9 +1554,9 @@ export default {
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
'settings.changeDevice.audioOut');
|
||||
APP.settings.setAudioOutputDeviceId(audioOutputDeviceId)
|
||||
.then(() => console.log('changed audio output device'))
|
||||
.then(() => logger.log('changed audio output device'))
|
||||
.catch((err) => {
|
||||
console.warn('Failed to change audio output device. ' +
|
||||
logger.warn('Failed to change audio output device. ' +
|
||||
'Default or previously set audio output device ' +
|
||||
'will be used instead.', err);
|
||||
APP.UI.setSelectedAudioOutputFromSettings();
|
||||
@@ -1608,11 +1648,12 @@ export default {
|
||||
APP.UI.onAvailableDevicesChanged(devices);
|
||||
});
|
||||
|
||||
this.deviceChangeListener = (devices) =>
|
||||
window.setTimeout(
|
||||
() => this._onDeviceListChanged(devices), 0);
|
||||
JitsiMeetJS.mediaDevices.addEventListener(
|
||||
JitsiMeetJS.events.mediaDevices.DEVICE_LIST_CHANGED,
|
||||
(devices) =>
|
||||
window.setTimeout(
|
||||
() => this._onDeviceListChanged(devices), 0));
|
||||
this.deviceChangeListener);
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -1711,14 +1752,25 @@ export default {
|
||||
* @param {string} name the event name
|
||||
* @param {int} value the value (it's int because google analytics supports
|
||||
* only int).
|
||||
* @param {string} label short text which provides more info about the event
|
||||
* which allows to distinguish between few event cases of the same name
|
||||
* NOTE: Should be used after conference.init
|
||||
*/
|
||||
logEvent(name, value) {
|
||||
logEvent(name, value, label) {
|
||||
if(JitsiMeetJS.analytics) {
|
||||
JitsiMeetJS.analytics.sendEvent(name, {value});
|
||||
JitsiMeetJS.analytics.sendEvent(name, {value, label});
|
||||
}
|
||||
if(room) {
|
||||
room.sendApplicationLog(JSON.stringify({name, value}));
|
||||
room.sendApplicationLog(JSON.stringify({name, value, label}));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Methods logs an application event given in the JSON format.
|
||||
* @param {string} logJSON an event to be logged in JSON format
|
||||
*/
|
||||
logJSON(logJSON) {
|
||||
if (room) {
|
||||
room.sendApplicationLog(logJSON);
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
12
config.js
12
config.js
@@ -26,7 +26,7 @@ var config = { // eslint-disable-line no-unused-vars
|
||||
desktopSharingChromeExtId: 'diibjkoicjeejcmhdnailmkgecihlobk',
|
||||
// The media sources to use when using screen sharing with the Chrome
|
||||
// extension.
|
||||
desktopSharingChromeSources: ['screen', 'window'],
|
||||
desktopSharingChromeSources: ['screen', 'window', 'tab'],
|
||||
// Required version of Chrome extension
|
||||
desktopSharingChromeMinExtVersion: '0.1',
|
||||
|
||||
@@ -78,3 +78,13 @@ var config = { // eslint-disable-line no-unused-vars
|
||||
// edit their profile.
|
||||
enableUserRolesBasedOnToken: false
|
||||
};
|
||||
|
||||
// Logging configuration
|
||||
var loggingConfig = { // eslint-disable-line no-unused-vars
|
||||
//default log level for the app and lib-jitsi-meet
|
||||
defaultLogLevel: 'trace',
|
||||
// Option to disable LogCollector (which stores the logs on CallStats)
|
||||
//disableLogCollector: true,
|
||||
// Logging level adjustments for verbose modules:
|
||||
'modules/xmpp/strophe.util.js': 'log'
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global APP, JitsiMeetJS, config */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import AuthHandler from './modules/UI/authentication/AuthHandler';
|
||||
import jitsiLocalStorage from './modules/util/JitsiLocalStorage';
|
||||
|
||||
@@ -84,7 +86,7 @@ function connect(id, password, roomName) {
|
||||
|
||||
function handleConnectionFailed(err) {
|
||||
unsubscribe();
|
||||
console.error("CONNECTION FAILED:", err);
|
||||
logger.error("CONNECTION FAILED:", err);
|
||||
reject(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,36 +29,6 @@ html, body, input, textarea, keygen, select, button {
|
||||
color: #636363;
|
||||
}
|
||||
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 5px 7px;
|
||||
color: $inputColor;
|
||||
border-radius: $borderRadius;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
border:1px solid $inputBorderColor;
|
||||
background-color: $inputBackground;
|
||||
outline: none; /* removes the default outline */
|
||||
resize: none; /* prevents the user-resizing, adjust to taste */
|
||||
}
|
||||
|
||||
@include placeholder {
|
||||
color: $placeHolderColor;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
resize: none;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
button.no-icon {
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
margin: 0;
|
||||
vertical-align: baseline;
|
||||
@@ -75,10 +45,26 @@ input[type="reset"], input[type="submit"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
resize: none;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
outline: none; /* removes the default outline */
|
||||
resize: none; /* prevents the user-resizing, adjust to taste */
|
||||
}
|
||||
|
||||
button {
|
||||
color: #FFF;
|
||||
background-color: $buttonBackground;
|
||||
border-radius: $borderRadius;
|
||||
|
||||
&.no-icon {
|
||||
padding: 0 1em;
|
||||
}
|
||||
}
|
||||
|
||||
button,
|
||||
@@ -132,38 +118,6 @@ form {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides an element.
|
||||
*/
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an element.
|
||||
*/
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an inline element.
|
||||
*/
|
||||
.show-inline {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a flex element.
|
||||
*/
|
||||
.show-flex {
|
||||
display: -webkit-box !important;
|
||||
display: -moz-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: -webkit-flex !important;
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tooltips
|
||||
**/
|
||||
@@ -185,18 +139,6 @@ form {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
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;
|
||||
|
||||
@@ -107,6 +107,10 @@
|
||||
float: left;
|
||||
padding-left: 5px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
width: 95%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#chat_container .timestamp {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
font-size: 12px;
|
||||
bottom: 0px;
|
||||
margin: 0;
|
||||
margin-top: 16px;
|
||||
margin-top: 12px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -13,18 +13,24 @@
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-security,
|
||||
.icon-security-locked {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
#contacts {
|
||||
|
||||
>li {
|
||||
color: $defaultSideBarFontColor;
|
||||
display: block;
|
||||
list-style-type: none;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
color: #FFF;
|
||||
font-size: 10pt;
|
||||
padding: 6px 10%;
|
||||
color: $baseLight;
|
||||
font-size: 16px;
|
||||
padding: 0 10%;
|
||||
height: 27px;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
@@ -36,6 +42,7 @@
|
||||
vertical-align: middle;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
line-height: 1.5em;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
z-index: 1; // Set z-index to make element visible
|
||||
width: 17px;
|
||||
width: $hideFilmstripButtonWidth;
|
||||
|
||||
button {
|
||||
font-size: 14px;
|
||||
@@ -50,9 +50,10 @@
|
||||
position:relative;
|
||||
height:196px;
|
||||
padding: 0;
|
||||
padding-left: 17px;
|
||||
bottom: 0;
|
||||
width:auto;
|
||||
border: 2px solid transparent;
|
||||
border: $thumbnailsBorder solid transparent;
|
||||
z-index: 5;
|
||||
transition: bottom 2s;
|
||||
overflow: visible !important;
|
||||
@@ -66,7 +67,7 @@
|
||||
display: none;
|
||||
position: relative;
|
||||
background-size: contain;
|
||||
border: 2px solid transparent;
|
||||
border: $thumbnailVideoBorder solid transparent;
|
||||
border-radius:1px;
|
||||
margin: 0 $thumbnailVideoMargin;
|
||||
|
||||
@@ -83,7 +84,7 @@
|
||||
-webkit-animation-name: greyPulse;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
border: 2px solid $videoThumbnailSelected !important;
|
||||
border: $thumbnailVideoBorder solid $videoThumbnailSelected !important;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailSelected,
|
||||
0 0 3px $videoThumbnailSelected !important;
|
||||
}
|
||||
@@ -97,7 +98,7 @@
|
||||
*/
|
||||
&:hover {
|
||||
cursor: hand;
|
||||
border: 2px solid $videoThumbnailHovered;
|
||||
border: $thumbnailVideoBorder solid $videoThumbnailHovered;
|
||||
box-shadow: inset 0 0 3px $videoThumbnailHovered,
|
||||
0 0 3px $videoThumbnailHovered;
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
@include border-radius(3px);
|
||||
padding: 40px 38px 44px;
|
||||
color: #fff;
|
||||
background: lighten(desaturate($defaultBackground, 70%), 20%);
|
||||
background: $inlayColorBg;
|
||||
text-align: center;
|
||||
|
||||
&__title {
|
||||
margin: 12px 0;
|
||||
margin: 17px 0;
|
||||
padding-bottom: 17px;
|
||||
color: $popoverFontColor;
|
||||
font-size: 21px;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
border-bottom: 1px solid $inlayBorderColor;
|
||||
}
|
||||
|
||||
&__text {
|
||||
@@ -26,4 +26,8 @@
|
||||
margin: 0 10px;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
&__button {
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,13 @@
|
||||
/*-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);*/
|
||||
/*box-shadow: 0 5px 10px rgba(0, 0, 0, 0.4);*/
|
||||
white-space: normal;
|
||||
margin-top: -10px;
|
||||
margin-top: -$popoverMenuPadding;
|
||||
|
||||
&__menu-padding {
|
||||
height: 10px;
|
||||
height: $popoverMenuPadding;
|
||||
width: 100px;
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
bottom: -$popoverMenuPadding;
|
||||
}
|
||||
|
||||
&__showmore {
|
||||
|
||||
@@ -63,7 +63,15 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
@include transform(translate(-50%, -50%))
|
||||
@include transform(translate(-50%, -50%));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the maximum width and height
|
||||
**/
|
||||
@mixin maxSize($value) {
|
||||
max-width: $value;
|
||||
max-height: $value;
|
||||
}
|
||||
|
||||
@mixin transform($func) {
|
||||
|
||||
@@ -16,30 +16,20 @@
|
||||
* Labels inside the side panel.
|
||||
*/
|
||||
label {
|
||||
color: $defaultColor;
|
||||
color: $baseLight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form elements and blocks.
|
||||
*/
|
||||
input, select, a,
|
||||
.sideToolbarBlock, .input-control, .button-control {
|
||||
.sideToolbarBlock, .form-control, .button-control {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
margin-left: 10%;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify colors for edit elements.
|
||||
*/
|
||||
select, input[type="button"], input[type="text"], input[type="reset"],
|
||||
input[type="submit"] {
|
||||
color: $inputColor;
|
||||
background: $inputBackground;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify styling of elements inside a block.
|
||||
*/
|
||||
@@ -70,20 +60,24 @@
|
||||
box-sizing: border-box;
|
||||
color: #FFF;
|
||||
|
||||
.input-control {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Titles and subtitles of inner containers.
|
||||
*/
|
||||
div.title, div.subTitle {
|
||||
margin: 10px 0;
|
||||
margin: 24px 0 11px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main title size.
|
||||
*/
|
||||
div.title {
|
||||
color: $defaultColor !important;
|
||||
font-size: 16px;
|
||||
color: $toolbarTitleColor;
|
||||
text-align: center;
|
||||
font-size: $toolbarTitleFontSize;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,8 +92,9 @@
|
||||
}
|
||||
|
||||
#toast-container.notification-bottom-right {
|
||||
$videoOffset: 2 * ($thumbnailVideoMargin + $thumbnailsBorder) + $thumbnailVideoBorder;
|
||||
bottom: 135px;
|
||||
right: 28px;
|
||||
right: $hideFilmstripButtonWidth + $videoOffset;
|
||||
}
|
||||
|
||||
#toast-container * {
|
||||
|
||||
@@ -252,7 +252,7 @@ a.button>#avatar {
|
||||
*/
|
||||
@include keyframes(slideInExt) {
|
||||
from { width: 0px; }
|
||||
to { width: 200px; } // TO FIX: Make this value a percentage.
|
||||
to { width: $sidebarWidth; } // TO FIX: Make this value a percentage.
|
||||
}
|
||||
|
||||
.slideInExt {
|
||||
@@ -260,7 +260,7 @@ a.button>#avatar {
|
||||
}
|
||||
|
||||
@include keyframes(slideOutExt) {
|
||||
from { width: 200px; } // TO FIX: Make this value a percentage.
|
||||
from { width: $sidebarWidth; } // TO FIX: Make this value a percentage.
|
||||
to { width: 0px; }
|
||||
}
|
||||
|
||||
|
||||
38
css/_utils.scss
Normal file
38
css/_utils.scss
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Hides an element.
|
||||
*/
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an element.
|
||||
*/
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an inline element.
|
||||
*/
|
||||
.show-inline {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows as a list item
|
||||
**/
|
||||
.show-list-item {
|
||||
display: list-item !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a flex element.
|
||||
*/
|
||||
.show-flex {
|
||||
display: -webkit-box !important;
|
||||
display: -moz-box !important;
|
||||
display: -ms-flexbox !important;
|
||||
display: -webkit-flex !important;
|
||||
display: flex !important;
|
||||
}
|
||||
@@ -14,9 +14,13 @@ $defaultToolbarSize: 50px;
|
||||
|
||||
// Video layout.
|
||||
$thumbnailToolbarHeight: 22px;
|
||||
$thumbnailIndicatorBorder: 0px;
|
||||
$thumbnailIndicatorSize: $thumbnailToolbarHeight;
|
||||
$thumbnailIndicatorBorder: 0;
|
||||
$thumbnailIndicatorSize: 3em;
|
||||
$thumbnailVideoMargin: 2px;
|
||||
$thumbnailsBorder: 2px;
|
||||
$thumbnailVideoBorder: 2px;
|
||||
$hideFilmstripButtonWidth: 17px;
|
||||
|
||||
|
||||
/**
|
||||
* Color variables.
|
||||
@@ -30,6 +34,8 @@ $tooltipBg: rgba(0,0,0, 0.7);
|
||||
/**
|
||||
* Toolbar
|
||||
*/
|
||||
$toolbarTitleColor: #FFFFFF;
|
||||
$toolbarTitleFontSize: 19px;
|
||||
$toolbarBackground: rgba(0, 0, 0, 0.5);
|
||||
$toolbarSelectBackground: rgba(0, 0, 0, .6);
|
||||
$toolbarBadgeBackground: #165ECC;
|
||||
@@ -71,7 +77,6 @@ $rateStarLabelColor: #333;
|
||||
$rateStarDefault: #ccc;
|
||||
$rateStarActivity: #165ecc;
|
||||
$rateStarSize: 34px;
|
||||
$feedbackCancelFontColor: #333;
|
||||
|
||||
/**
|
||||
* Notifications
|
||||
@@ -90,10 +95,10 @@ $notificationWidth: 215px;
|
||||
/**
|
||||
* Misc.
|
||||
*/
|
||||
$borderRadius: 4px;
|
||||
$borderRadius: 3px;
|
||||
$defaultWatermarkLink: '../images/watermark.png';
|
||||
$sidebarWidth: 200px;
|
||||
|
||||
$sidebarWidth: 220px;
|
||||
$popoverMenuPadding: 13px;
|
||||
$happySoftwareBackground: transparent;
|
||||
|
||||
/**
|
||||
@@ -117,14 +122,8 @@ $defaultDarkFontColor: #000;
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
//dropdown
|
||||
$selectFontColor: $defaultLightFontColor;
|
||||
$selectBg: $defaultBackground;
|
||||
$selectActiveBg: $defaultBackground;
|
||||
$selectActiveItemBg: $defaultDarkColor;
|
||||
//inputs
|
||||
$inputControlEmColor: #f29424;
|
||||
//buttons
|
||||
$linkFontColor: #489afe;
|
||||
$linkHoverFontColor: #287ade;
|
||||
|
||||
$linkHoverFontColor: #287ade;
|
||||
@@ -22,41 +22,97 @@
|
||||
height: 100%;
|
||||
background-color: black;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The toolbar of the video thumbnail.
|
||||
*/
|
||||
.videocontainer__toolbar,
|
||||
.videocontainer__toptoolbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
width: 100%;
|
||||
box-sizing: border-box; // Includes the padding in the 100% width.
|
||||
}
|
||||
/**
|
||||
* The toolbar of the video thumbnail.
|
||||
*/
|
||||
&__toolbar,
|
||||
&__toptoolbar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 3;
|
||||
width: 100%;
|
||||
box-sizing: border-box; // Includes the padding in the 100% width.
|
||||
}
|
||||
|
||||
.videocontainer__toolbar {
|
||||
bottom: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
height: $thumbnailToolbarHeight;
|
||||
}
|
||||
&__toolbar {
|
||||
bottom: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
height: $thumbnailToolbarHeight;
|
||||
}
|
||||
|
||||
.videocontainer__toptoolbar {
|
||||
$toolbarPadding: 5px;
|
||||
top: 0;
|
||||
padding: $toolbarPadding;
|
||||
padding-bottom: 0;
|
||||
height: $thumbnailIndicatorSize + $toolbarPadding;
|
||||
}
|
||||
&__toptoolbar {
|
||||
$toolbarPadding: 5px;
|
||||
top: 0;
|
||||
padding: $toolbarPadding;
|
||||
padding-bottom: 0;
|
||||
|
||||
.videocontainer__hoverOverlay {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
visibility: hidden;
|
||||
background: rgba(0,0,0,.6);
|
||||
z-index: 2;
|
||||
span.indicator {
|
||||
position: relative;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
line-height: $thumbnailIndicatorSize;
|
||||
display: none;
|
||||
padding: 0;
|
||||
margin-right: em(5, 8);
|
||||
float: left;
|
||||
@include circle($thumbnailIndicatorSize);
|
||||
box-sizing: border-box;
|
||||
z-index: 3;
|
||||
background: $dominantSpeakerBg;
|
||||
color: $thumbnailPictogramColor;
|
||||
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.indicatoricon {
|
||||
@include absoluteAligning();
|
||||
}
|
||||
|
||||
.connection {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
left: 0;
|
||||
@include transform(translate(0, -50%));
|
||||
|
||||
&_empty
|
||||
{
|
||||
color: #8B8B8B;/*#FFFFFF*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&_lost
|
||||
{
|
||||
color: #8B8B8B;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&_full
|
||||
{
|
||||
@include topLeft();
|
||||
color: #FFFFFF;/*#15A1ED*/
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-connection,
|
||||
.icon-connection-lost {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__hoverOverlay {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
visibility: hidden;
|
||||
background: rgba(0,0,0,.6);
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
#localVideoWrapper {
|
||||
@@ -217,72 +273,6 @@
|
||||
background: $connectionIndicatorBg;
|
||||
}
|
||||
|
||||
.videocontainer__toptoolbar span.indicator {
|
||||
position: relative;
|
||||
font-size: 8pt;
|
||||
text-align: center;
|
||||
line-height: $thumbnailToolbarHeight;
|
||||
display: none;
|
||||
padding: 0;
|
||||
margin-right: 5px;
|
||||
float: left;
|
||||
@include circle($thumbnailIndicatorSize);
|
||||
box-sizing: border-box;
|
||||
z-index: 3;
|
||||
background: $dominantSpeakerBg;
|
||||
color: $thumbnailPictogramColor;
|
||||
border: $thumbnailIndicatorBorder solid $thumbnailPictogramColor;
|
||||
|
||||
.indicatoricon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
@include transform(translateY(-50%));
|
||||
width: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
|
||||
height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
|
||||
line-height: $thumbnailIndicatorSize - 2 * $thumbnailIndicatorBorder;
|
||||
}
|
||||
|
||||
.connection {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 12px;
|
||||
height: 8px;
|
||||
|
||||
&_empty
|
||||
{
|
||||
@include topLeft();
|
||||
max-width: 12px;
|
||||
width: 12px;
|
||||
color: #8B8B8B;/*#FFFFFF*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&_lost
|
||||
{
|
||||
@include topLeft();
|
||||
max-width: 12px;
|
||||
width: 12px;
|
||||
color: #8B8B8B;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&_full
|
||||
{
|
||||
@include topLeft();
|
||||
max-width: 12px;
|
||||
width: 12px;
|
||||
color: #FFFFFF;/*#15A1ED*/
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-connection,
|
||||
.icon-connection-lost {
|
||||
font-size: 6pt;
|
||||
}
|
||||
}
|
||||
|
||||
.remotevideomenu
|
||||
{
|
||||
display: inline-block;
|
||||
@@ -399,8 +389,11 @@
|
||||
}
|
||||
|
||||
.userAvatar {
|
||||
@include circle(60px);
|
||||
@include maxSize(60px);
|
||||
@include absoluteAligning();
|
||||
border-radius: 50%;
|
||||
height: 50%;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.sharedVideoAvatar {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
.select2-container.aui-select2-container {
|
||||
background-color: transparent !important;
|
||||
margin-top: 2px;
|
||||
|
||||
a.select2-choice {
|
||||
height: 28px !important;
|
||||
@@ -55,6 +55,7 @@
|
||||
|
||||
.select2-result-label{
|
||||
font-size: 12px;
|
||||
color: $selectFontColor !important;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.input-control {
|
||||
.form-control {
|
||||
padding: 16px 0;
|
||||
|
||||
&:first-child {
|
||||
@@ -19,24 +19,6 @@
|
||||
font-weight: $labelFontWeight;
|
||||
}
|
||||
|
||||
&__input {
|
||||
margin-bottom: 8px;
|
||||
@include transition(all .2s ease-in);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: inherit;
|
||||
}
|
||||
|
||||
&::selection {
|
||||
background-color: $defaultDarkSelectionColor;
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: $errorColor;
|
||||
border-color: $errorColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__em {
|
||||
color: $inputControlEmColor;
|
||||
}
|
||||
32
css/components/_input-control.scss
Normal file
32
css/components/_input-control.scss
Normal file
@@ -0,0 +1,32 @@
|
||||
.input-control {
|
||||
@include transition(all .2s ease-in);
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 5px 7px;
|
||||
color: $inputColor;
|
||||
border-radius: $borderRadius;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
border:1px solid $inputBorderColor;
|
||||
background-color: $inputBackground;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: inherit;
|
||||
}
|
||||
|
||||
&::selection {
|
||||
background-color: $defaultDarkSelectionColor;
|
||||
}
|
||||
|
||||
|
||||
&.error {
|
||||
color: $errorColor;
|
||||
border-color: $errorColor;
|
||||
}
|
||||
}
|
||||
|
||||
@include placeholder {
|
||||
color: $placeHolderColor;
|
||||
}
|
||||
11
css/components/_link.scss
Normal file
11
css/components/_link.scss
Normal file
@@ -0,0 +1,11 @@
|
||||
.link {
|
||||
cursor: pointer;
|
||||
color: $linkFontColor;
|
||||
@include transition(color .1s ease-out);
|
||||
|
||||
&:hover {
|
||||
color: $linkHoverFontColor;
|
||||
text-decoration: underline;
|
||||
@include transition(color .1s ease-in);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
@import 'toastr';
|
||||
@import 'base';
|
||||
@import 'utils';
|
||||
@import 'overlay/overlay';
|
||||
@import 'inlay';
|
||||
@import 'reload_overlay/reload_overlay';
|
||||
@@ -55,9 +56,11 @@
|
||||
@import 'jquery.contextMenu';
|
||||
@import 'keyboard-shortcuts';
|
||||
@import 'redirect_page';
|
||||
@import 'input-control/input-control';
|
||||
@import 'components/form-control';
|
||||
@import 'components/link';
|
||||
@import 'shortcuts/main';
|
||||
@import 'buttons/button-control';
|
||||
@import 'components/button-control';
|
||||
@import 'components/_input-control.scss';
|
||||
@import "modals/invite/invite";
|
||||
@import "connection-info";
|
||||
@import 'aui-components/dropdown';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
visibility: visible;
|
||||
height: auto;
|
||||
|
||||
h3 {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: $auiDialogColor;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.input-control:not(:last-child) {
|
||||
.form-control:not(:last-child) {
|
||||
border-bottom: 1px solid $auiBorderColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,20 +62,18 @@
|
||||
text-align: center;
|
||||
padding: 10px 40px 20px 40px;
|
||||
|
||||
.input-control{
|
||||
&__input {
|
||||
background-color: $feedbackInputBg;
|
||||
color: $feedbackInputTextColor;
|
||||
.input-control {
|
||||
background-color: $feedbackInputBg;
|
||||
color: $feedbackInputTextColor;
|
||||
|
||||
&::-webkit-input-placeholder {
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
&::-moz-placeholder { /* Firefox 19+ */
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
&::-webkit-input-placeholder {
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
&::-moz-placeholder { /* Firefox 19+ */
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
color: $feedbackInputPlaceholderColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,4 @@
|
||||
#reloadProgressBar {
|
||||
width: 180px;
|
||||
margin: 5px auto;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,14 @@
|
||||
/**
|
||||
* Base
|
||||
*/
|
||||
$baseLight: #FFFFFF;
|
||||
|
||||
/**
|
||||
* Controls
|
||||
*/
|
||||
$controlBackground: $baseLight;
|
||||
$controlColor: #333333;
|
||||
|
||||
/**
|
||||
* Buttons
|
||||
*/
|
||||
@@ -17,7 +28,7 @@ $buttonLinkColor: #0090e8;
|
||||
|
||||
$primaryButtonBackground: #3572b0;
|
||||
$primaryButtonHoverBackground: #2a67a5;
|
||||
$primaryButtonColor: #fff;
|
||||
$primaryButtonColor: $baseLight;
|
||||
$primaryButtonFontWeight: 400;
|
||||
|
||||
$buttonShadowColor: #192d4f;
|
||||
@@ -38,14 +49,20 @@ $uploadConnectionIconColor: #ffa800;
|
||||
**/
|
||||
$auiDialogColor: #333;
|
||||
$auiDialogBg: #f5f5f5;
|
||||
$auiDialogContentBg: #fff;
|
||||
$auiDialogContentBg: $baseLight;
|
||||
$auiBorderColor: #ccc;
|
||||
$dialogTitleFontWeight: 400;
|
||||
|
||||
/**
|
||||
* Inlay colors
|
||||
**/
|
||||
$inlayColorBg: lighten($defaultBackground, 20%);
|
||||
$inlayBorderColor: lighten($auiDialogContentBg, 10%);
|
||||
|
||||
// Main controls
|
||||
$inputBackground: #fff;
|
||||
$inputBackground: $controlBackground;
|
||||
$inputBorderColor: #ccc;
|
||||
$inputColor: #333;
|
||||
$inputColor: $controlColor;
|
||||
$placeHolderColor: #a7a7a7;
|
||||
$readOnlyInputColor: #a7a7a7;
|
||||
$defaultDarkSelectionColor: #ccc;
|
||||
@@ -57,10 +74,22 @@ $linkHoverFontColor: darken(#3572b0, 10%);
|
||||
$dropdownColor: #333;
|
||||
$errorColor: #c61600;
|
||||
|
||||
// Feedback colors
|
||||
$feedbackCancelFontColor: #333;
|
||||
|
||||
// Popover colors
|
||||
$popoverBg: #000;
|
||||
$popoverFontColor: #ffffff;
|
||||
$popupMenuSelectedItemBackground: rgba(256, 256, 256, .2);
|
||||
|
||||
// Toolbar
|
||||
$splitterColor: #ccc;
|
||||
$splitterColor: #ccc;
|
||||
|
||||
/**
|
||||
* Forms
|
||||
*/
|
||||
//dropdown
|
||||
$selectFontColor: $controlColor;
|
||||
$selectBg: $controlBackground;
|
||||
$selectActiveBg: darken($controlBackground, 5%);
|
||||
$selectActiveItemBg: darken($controlBackground, 20%);
|
||||
|
||||
2
debian/changelog
vendored
2
debian/changelog
vendored
@@ -1,4 +1,4 @@
|
||||
jitsi-meet (1.0.1-1) unstable; urgency=low
|
||||
jitsi-meet-web (1.0.1-1) unstable; urgency=low
|
||||
|
||||
* Initial release. (Closes: #760485)
|
||||
|
||||
|
||||
26
debian/control
vendored
26
debian/control
vendored
@@ -1,4 +1,4 @@
|
||||
Source: jitsi-meet
|
||||
Source: jitsi-meet-web
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Jitsi Team <dev@jitsi.org>
|
||||
@@ -7,10 +7,10 @@ Build-Depends: debhelper (>= 8.0.0)
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: https://jitsi.org/meet
|
||||
|
||||
Package: jitsi-meet
|
||||
Package: jitsi-meet-web
|
||||
Replaces: jitsi-meet (<= 1.0.1525-1)
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, jitsi-videobridge, jitsi-meet-prosody,
|
||||
openjdk-8-jre-headless | nginx
|
||||
Depends: ${misc:Depends}
|
||||
Description: WebRTC JavaScript video conferences
|
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
|
||||
Videobridge to provide high quality, scalable video conferences.
|
||||
@@ -19,9 +19,25 @@ Description: WebRTC JavaScript video conferences
|
||||
forwarding and relaying, configured to work with jetty instance
|
||||
running embedded into Jitsi Videobridge
|
||||
|
||||
Package: jitsi-meet-web-config
|
||||
Architecture: all
|
||||
Depends: openssl, openjdk-8-jre-headless | nginx | apache2,
|
||||
jitsi-meet-web
|
||||
Description: Configuration for web serving of Jitsi Meet
|
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
|
||||
Videobridge to provide high quality, scalable video conferences.
|
||||
.
|
||||
It is a web interface to Jitsi Videobridge for audio and video
|
||||
forwarding and relaying, configured to work with jetty instance
|
||||
running embedded into Jitsi Videobridge or using a webserver Nginx or
|
||||
Apache2.
|
||||
.
|
||||
This package contains configuration for Nginx to be used with
|
||||
Jitsi Meet.
|
||||
|
||||
Package: jitsi-meet-prosody
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, openssl, prosody | prosody-trunk, jitsi-videobridge, jicofo
|
||||
Depends: openssl, prosody | prosody-trunk, jitsi-meet-web
|
||||
Description: Prosody configuration for Jitsi Meet
|
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi
|
||||
Videobridge to provide high quality, scalable video conferences.
|
||||
|
||||
4
debian/jitsi-meet-prosody.config
vendored
4
debian/jitsi-meet-prosody.config
vendored
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
# Source debconf library.
|
||||
. /usr/share/debconf/confmodule
|
||||
62
debian/jitsi-meet-prosody.postinst
vendored
62
debian/jitsi-meet-prosody.postinst
vendored
@@ -21,13 +21,49 @@ set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
|
||||
. /etc/jitsi/videobridge/config
|
||||
|
||||
. /etc/jitsi/jicofo/config
|
||||
|
||||
# loading debconf
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
# try to get host from jitsi-videobridge
|
||||
db_get jitsi-videobridge/jvb-hostname
|
||||
if [ -z "$RET" ] ; then
|
||||
# server hostname
|
||||
db_set jitsi-videobridge/jvb-hostname "localhost"
|
||||
db_input critical jitsi-videobridge/jvb-hostname || true
|
||||
db_go
|
||||
fi
|
||||
JVB_HOSTNAME="$RET"
|
||||
|
||||
db_get jitsi-videobridge/jvbsecret
|
||||
if [ -z "$RET" ] ; then
|
||||
db_input critical jitsi-videobridge/jvbsecret || true
|
||||
db_go
|
||||
fi
|
||||
JVB_SECRET="$RET"
|
||||
|
||||
db_get jicofo/jicofo-authuser
|
||||
if [ -z "$RET" ] ; then
|
||||
db_input critical jicofo/jicofo-authuser || true
|
||||
db_go
|
||||
fi
|
||||
JICOFO_AUTH_USER="$RET"
|
||||
|
||||
db_get jicofo/jicofo-authpassword
|
||||
if [ -z "$RET" ] ; then
|
||||
db_input critical jicofo/jicofo-authpassword || true
|
||||
db_go
|
||||
fi
|
||||
JICOFO_AUTH_PASSWORD="$RET"
|
||||
|
||||
db_get jicofo/jicofosecret
|
||||
if [ -z "$RET" ] ; then
|
||||
db_input critical jicofo/jicofosecret || true
|
||||
db_go
|
||||
fi
|
||||
JICOFO_SECRET="$RET"
|
||||
|
||||
JICOFO_AUTH_DOMAIN="auth.$JVB_HOSTNAME"
|
||||
|
||||
# detect dpkg-reconfigure, just delete old links
|
||||
db_get jitsi-meet-prosody/jvb-hostname
|
||||
JVB_HOSTNAME_OLD=$RET
|
||||
@@ -38,7 +74,7 @@ case "$1" in
|
||||
fi
|
||||
|
||||
# stores the hostname so we will reuse it later, like in purge
|
||||
db_set jitsi-meet-prosody/jvb-hostname $JVB_HOSTNAME
|
||||
db_set jitsi-meet-prosody/jvb-hostname "$JVB_HOSTNAME"
|
||||
|
||||
# and we're done with debconf
|
||||
db_stop
|
||||
@@ -68,21 +104,21 @@ case "$1" in
|
||||
fi
|
||||
fi
|
||||
# UPGRADE to server side focus check if focus is configured
|
||||
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "VirtualHost \"auth.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG; then
|
||||
echo -e "\nVirtualHost \"auth.$JVB_HOSTNAME\"" >> $PROSODY_HOST_CONFIG
|
||||
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "VirtualHost \"$JICOFO_AUTH_DOMAIN\"" $PROSODY_HOST_CONFIG; then
|
||||
echo -e "\nVirtualHost \"$JICOFO_AUTH_DOMAIN\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " authentication = \"internal_plain\"\n" >> $PROSODY_HOST_CONFIG
|
||||
sed -i "s/Component \"conference.$JVB_HOSTNAME\" \"muc\"/Component \"conference.$JVB_HOSTNAME\" \"muc\"\nadmins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\" }\n/g" $PROSODY_HOST_CONFIG
|
||||
sed -i "s/Component \"conference.$JVB_HOSTNAME\" \"muc\"/Component \"conference.$JVB_HOSTNAME\" \"muc\"\nadmins = { \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\" }\n/g" $PROSODY_HOST_CONFIG
|
||||
echo -e "Component \"focus.$JVB_HOSTNAME\"" >> $PROSODY_HOST_CONFIG
|
||||
echo -e " component_secret=\"$JICOFO_SECRET\"\n" >> $PROSODY_HOST_CONFIG
|
||||
PROSODY_CREATE_JICOFO_USER="true"
|
||||
# UPGRADE to server side focus on old config(/etc/prosody/prosody.cfg.lua)
|
||||
elif [ ! -f $PROSODY_HOST_CONFIG ] && ! grep -q "VirtualHost \"auth.$JVB_HOSTNAME\"" $PROSODY_CONFIG_OLD; then
|
||||
echo -e "\nVirtualHost \"auth.$JVB_HOSTNAME\"" >> $PROSODY_CONFIG_OLD
|
||||
elif [ ! -f $PROSODY_HOST_CONFIG ] && ! grep -q "VirtualHost \"$JICOFO_AUTH_DOMAIN\"" $PROSODY_CONFIG_OLD; then
|
||||
echo -e "\nVirtualHost \"$JICOFO_AUTH_DOMAIN\"" >> $PROSODY_CONFIG_OLD
|
||||
echo -e " authentication = \"internal_plain\"\n" >> $PROSODY_CONFIG_OLD
|
||||
if ! grep -q "admins = { }" $PROSODY_CONFIG_OLD; then
|
||||
echo -e "admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\" }\n" >> $PROSODY_CONFIG_OLD
|
||||
echo -e "admins = { \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\" }\n" >> $PROSODY_CONFIG_OLD
|
||||
else
|
||||
sed -i "s/admins = { }/admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\" }\n/g" $PROSODY_CONFIG_OLD
|
||||
sed -i "s/admins = { }/admins = { \"$JICOFO_AUTH_USER@$JICOFO_AUTH_DOMAIN\" }\n/g" $PROSODY_CONFIG_OLD
|
||||
fi
|
||||
echo -e "Component \"focus.$JVB_HOSTNAME\"" >> $PROSODY_CONFIG_OLD
|
||||
echo -e " component_secret=\"$JICOFO_SECRET\"\n" >> $PROSODY_CONFIG_OLD
|
||||
@@ -109,8 +145,6 @@ case "$1" in
|
||||
|
||||
if [ "$PROSODY_CONFIG_PRESENT" = "false" ]; then
|
||||
invoke-rc.d prosody restart
|
||||
invoke-rc.d jitsi-videobridge restart
|
||||
invoke-rc.d jicofo restart
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
3
debian/jitsi-meet-prosody.postrm
vendored
3
debian/jitsi-meet-prosody.postrm
vendored
@@ -36,6 +36,9 @@ case "$1" in
|
||||
rm -f /etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua
|
||||
rm -f /etc/prosody/conf.d/$JVB_HOSTNAME.cfg.lua
|
||||
fi
|
||||
|
||||
# Clear the debconf variable
|
||||
db_purge
|
||||
;;
|
||||
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
|
||||
26
debian/jitsi-meet-prosody.templates
vendored
26
debian/jitsi-meet-prosody.templates
vendored
@@ -2,3 +2,29 @@ Template: jitsi-meet-prosody/jvb-hostname
|
||||
Type: string
|
||||
_Description: The hostname of the current installation:
|
||||
The value for the hostname that is set in Jitsi Videobridge installation.
|
||||
|
||||
Template: jitsi-videobridge/jvb-hostname
|
||||
Type: string
|
||||
_Description: The hostname of the current installation:
|
||||
The value for the hostname that is set in Jitsi Videobridge installation.
|
||||
|
||||
Template: jitsi-videobridge/jvbsecret
|
||||
Type: password
|
||||
_Description: Jitsi Videobridge Component secret:
|
||||
The secret used by Jitsi Videobridge to connect to xmpp server as component.
|
||||
|
||||
Template: jicofo/jicofo-authuser
|
||||
Type: string
|
||||
Default: focus
|
||||
_Description: Jicofo username:
|
||||
The jicofo needs an authenticated admin user to connect to xmpp server.
|
||||
|
||||
Template: jicofo/jicofo-authpassword
|
||||
Type: password
|
||||
_Description: Jicofo user password:
|
||||
The secret used to connect to xmpp server as jicofo user.
|
||||
|
||||
Template: jicofo/jicofosecret
|
||||
Type: password
|
||||
_Description: Jicofo Component secret:
|
||||
The secret used to connect to xmpp server as component
|
||||
|
||||
17
debian/jitsi-meet-tokens.postinst
vendored
17
debian/jitsi-meet-tokens.postinst
vendored
@@ -21,17 +21,12 @@ set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
|
||||
if [ -f "/etc/jitsi/videobridge/config" ] ; then
|
||||
. /etc/jitsi/videobridge/config
|
||||
fi
|
||||
|
||||
if [ -f "/etc/jitsi/jicofo/config" ] ; then
|
||||
. /etc/jitsi/jicofo/config
|
||||
fi
|
||||
|
||||
# loading debconf
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
db_get jitsi-meet-prosody/jvb-hostname
|
||||
JVB_HOSTNAME="$RET"
|
||||
|
||||
db_get jitsi-meet-tokens/appid
|
||||
if [ "$RET" = "false" ] ; then
|
||||
echo "Application ID is mandatory"
|
||||
@@ -45,14 +40,10 @@ case "$1" in
|
||||
fi
|
||||
APP_SECRET=$RET
|
||||
|
||||
# We can adjust Prosody config only if there is Jvb or Jicofo domain configured
|
||||
PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua"
|
||||
if [ ! -f "$PROSODY_HOST_CONFIG" ] ; then
|
||||
PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JICOFO_HOSTNAME.cfg.lua"
|
||||
fi
|
||||
|
||||
# Store config filename for purge
|
||||
db_set jitsi-meet-prosody/prosody_config $PROSODY_HOST_CONFIG
|
||||
db_set jitsi-meet-prosody/prosody_config "$PROSODY_HOST_CONFIG"
|
||||
|
||||
db_stop
|
||||
|
||||
|
||||
2
debian/jitsi-meet-tokens.postrm
vendored
2
debian/jitsi-meet-tokens.postrm
vendored
@@ -52,6 +52,8 @@ case "$1" in
|
||||
;;
|
||||
|
||||
purge)
|
||||
# Clear the debconf variable
|
||||
db_purge
|
||||
;;
|
||||
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
# postinst script for jitsi-meet
|
||||
# postinst script for jitsi-meet-web-config
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
@@ -20,13 +20,19 @@ set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
|
||||
JVB_ETC_CONFIG="/etc/jitsi/videobridge/config"
|
||||
|
||||
. $JVB_ETC_CONFIG
|
||||
|
||||
# loading debconf
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
# try to get host from jitsi-videobridge
|
||||
db_get jitsi-videobridge/jvb-hostname
|
||||
if [ -z "$RET" ] ; then
|
||||
# server hostname
|
||||
db_set jitsi-videobridge/jvb-hostname "localhost"
|
||||
db_input critical jitsi-videobridge/jvb-hostname || true
|
||||
db_go
|
||||
fi
|
||||
JVB_HOSTNAME="$RET"
|
||||
|
||||
# detect dpkg-reconfigure
|
||||
RECONFIGURING="false"
|
||||
db_get jitsi-meet/jvb-hostname
|
||||
@@ -49,22 +55,54 @@ case "$1" in
|
||||
if [ "$NGINX_INSTALL_CHECK" = "installed" ] || [ "$NGINX_INSTALL_CHECK" = "unpacked" ] ; then
|
||||
FORCE_NGINX="true"
|
||||
fi
|
||||
APACHE_INSTALL_CHECK="$(dpkg-query -f '${Status}' -W 'apache2' 2>/dev/null | awk '{print $3}' || true)"
|
||||
if [ "$APACHE_INSTALL_CHECK" = "installed" ] || [ "$APACHE_INSTALL_CHECK" = "unpacked" ] ; then
|
||||
FORCE_APACHE="true"
|
||||
fi
|
||||
|
||||
# SSL for nginx
|
||||
db_get jitsi-meet/cert-choice
|
||||
CERT_CHOICE="$RET"
|
||||
UPLOADED_CERT_CHOICE="A certificate is available and the files are uploaded on the server"
|
||||
# if first time config ask for certs, or if we are reconfiguring
|
||||
if [ -z "$JVB_HOSTNAME_OLD" ] || [ "$RECONFIGURING" = "true" ] ; then
|
||||
# SSL for nginx
|
||||
db_get jitsi-meet/cert-choice
|
||||
CERT_CHOICE="$RET"
|
||||
UPLOADED_CERT_CHOICE="A certificate is available and the files are uploaded on the server"
|
||||
|
||||
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
|
||||
db_set jitsi-meet/cert-path-key "/etc/ssl/$JVB_HOSTNAME.key"
|
||||
db_input critical jitsi-meet/cert-path-key || true
|
||||
db_go
|
||||
db_get jitsi-meet/cert-path-key
|
||||
CERT_KEY="$RET"
|
||||
db_set jitsi-meet/cert-path-crt "/etc/ssl/$JVB_HOSTNAME.crt"
|
||||
db_input critical jitsi-meet/cert-path-crt || true
|
||||
db_go
|
||||
db_get jitsi-meet/cert-path-crt
|
||||
CERT_CRT="$RET"
|
||||
else
|
||||
# create self-signed certs
|
||||
CERT_KEY="/etc/jitsi/meet/$JVB_HOSTNAME.key"
|
||||
CERT_CRT="/etc/jitsi/meet/$JVB_HOSTNAME.crt"
|
||||
HOST="$( (hostname -s; echo localhost) | head -n 1)"
|
||||
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)"
|
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \
|
||||
"/O=$DOMAIN/OU=$HOST/CN=$JVB_HOSTNAME/emailAddress=webmaster@$HOST.$DOMAIN" \
|
||||
-keyout $CERT_KEY \
|
||||
-out $CERT_CRT
|
||||
fi
|
||||
fi
|
||||
|
||||
# jitsi meet
|
||||
JITSI_MEET_CONFIG="/etc/jitsi/meet/$JVB_HOSTNAME-config.js"
|
||||
if [ ! -f $JITSI_MEET_CONFIG ] ; then
|
||||
cp /usr/share/doc/jitsi-meet/config.js $JITSI_MEET_CONFIG
|
||||
cp /usr/share/doc/jitsi-meet-web/config.js $JITSI_MEET_CONFIG
|
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" $JITSI_MEET_CONFIG
|
||||
fi
|
||||
|
||||
# this is new install let's configure jvb to serve meet
|
||||
if [[ -z $FORCE_NGINX && ( -z $JVB_HOSTNAME_OLD || "$JVB_SERVE" = "true" ) ]] ; then
|
||||
# no-nginx, no-apache installed on machine, this is new install or reconfiguring old one which have jvb_serve set
|
||||
if [[ -z "$FORCE_NGINX" && -z "$FORCE_APACHE" && ( -z "$JVB_HOSTNAME_OLD" || ( "$JVB_SERVE" = "true" && "$RECONFIGURING" = "true" )) ]] ; then
|
||||
|
||||
JVB_ETC_CONFIG="/etc/jitsi/videobridge/config"
|
||||
JVB_CONFIG="/etc/jitsi/videobridge/sip-communicator.properties"
|
||||
|
||||
# this is a reconfigure, lets just delete old links
|
||||
@@ -112,34 +150,19 @@ case "$1" in
|
||||
chmod 755 /etc/authbind/byport/443
|
||||
fi
|
||||
|
||||
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
|
||||
# create jks from uploaded certs
|
||||
openssl pkcs12 -export \
|
||||
-in /etc/ssl/$JVB_HOSTNAME.crt \
|
||||
-inkey /etc/ssl/$JVB_HOSTNAME.key \
|
||||
-passout pass:changeit > /etc/jitsi/videobridge/$JVB_HOSTNAME.p12
|
||||
keytool -importkeystore \
|
||||
-srckeystore /etc/jitsi/videobridge/$JVB_HOSTNAME.p12 \
|
||||
-destkeystore /etc/jitsi/videobridge/$JVB_HOSTNAME.jks \
|
||||
-srcstoretype pkcs12 \
|
||||
-noprompt -storepass changeit -srcstorepass changeit
|
||||
else
|
||||
# create jks from self-signed certs
|
||||
openssl pkcs12 -export \
|
||||
-in /var/lib/prosody/$JVB_HOSTNAME.crt \
|
||||
-inkey /var/lib/prosody/$JVB_HOSTNAME.key \
|
||||
-passout pass:changeit > /etc/jitsi/videobridge/$JVB_HOSTNAME.p12
|
||||
keytool -importkeystore \
|
||||
-srckeystore /etc/jitsi/videobridge/$JVB_HOSTNAME.p12 \
|
||||
-destkeystore /etc/jitsi/videobridge/$JVB_HOSTNAME.jks \
|
||||
-srcstoretype pkcs12 \
|
||||
-noprompt -storepass changeit -srcstorepass changeit
|
||||
fi
|
||||
CERT_P12="/etc/jitsi/videobridge/$JVB_HOSTNAME.p12"
|
||||
CERT_JKS="/etc/jitsi/videobridge/$JVB_HOSTNAME.jks"
|
||||
# create jks from certs
|
||||
openssl pkcs12 -export \
|
||||
-in $CERT_CRT -inkey $CERT_KEY -passout pass:changeit > $CERT_P12
|
||||
keytool -importkeystore -destkeystore $CERT_JKS \
|
||||
-srckeystore $CERT_P12 -srcstoretype pkcs12 \
|
||||
-noprompt -storepass changeit -srcstorepass changeit
|
||||
|
||||
db_set jitsi-meet/jvb-serve "true"
|
||||
|
||||
invoke-rc.d jitsi-videobridge restart
|
||||
elif [[ "$FORCE_NGINX" = "true" || ( -n $JVB_HOSTNAME_OLD && "$JVB_SERVE" = "false" ) ]] ; then
|
||||
elif [[ "$FORCE_NGINX" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
|
||||
# this is a reconfigure, lets just delete old links
|
||||
if [ "$RECONFIGURING" = "true" ] ; then
|
||||
rm -f /etc/nginx/sites-enabled/$JVB_HOSTNAME_OLD.conf
|
||||
@@ -148,7 +171,7 @@ case "$1" in
|
||||
|
||||
# nginx conf
|
||||
if [ ! -f /etc/nginx/sites-available/$JVB_HOSTNAME.conf ] ; then
|
||||
cp /usr/share/doc/jitsi-meet/jitsi-meet.example /etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
cp /usr/share/doc/jitsi-meet-web/jitsi-meet.example /etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
if [ ! -f /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf ] ; then
|
||||
ln -s /etc/nginx/sites-available/$JVB_HOSTNAME.conf /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf
|
||||
fi
|
||||
@@ -156,28 +179,47 @@ case "$1" in
|
||||
fi
|
||||
|
||||
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
|
||||
db_set jitsi-meet/cert-path-key "/etc/ssl/$JVB_HOSTNAME.key"
|
||||
db_input critical jitsi-meet/cert-path-key || true
|
||||
db_go
|
||||
db_get jitsi-meet/cert-path-key
|
||||
CERT_KEY="$RET"
|
||||
db_set jitsi-meet/cert-path-crt "/etc/ssl/$JVB_HOSTNAME.crt"
|
||||
db_input critical jitsi-meet/cert-path-crt || true
|
||||
db_go
|
||||
db_get jitsi-meet/cert-path-crt
|
||||
CERT_CRT="$RET"
|
||||
# replace self-signed certificate paths with user provided ones
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY | sed 's/\./\\\./g')
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/ssl_certificate_key\ \/var\/lib\/prosody\/.*key/ssl_certificate_key\ $CERT_KEY_ESC/g" \
|
||||
sed -i "s/ssl_certificate_key\ \/etc\/jitsi\/meet\/.*key/ssl_certificate_key\ $CERT_KEY_ESC/g" \
|
||||
/etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT | sed 's/\./\\\./g')
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/ssl_certificate\ \/var\/lib\/prosody\/.*crt/ssl_certificate\ $CERT_CRT_ESC/g" \
|
||||
sed -i "s/ssl_certificate\ \/etc\/jitsi\/meet\/.*crt/ssl_certificate\ $CERT_CRT_ESC/g" \
|
||||
/etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
fi
|
||||
|
||||
invoke-rc.d nginx reload
|
||||
elif [[ "$FORCE_APACHE" = "true" && ( -z "$JVB_HOSTNAME_OLD" || "$RECONFIGURING" = "true" ) ]] ; then
|
||||
# this is a reconfigure, lets just delete old links
|
||||
if [ "$RECONFIGURING" = "true" ] ; then
|
||||
a2dissite $JVB_HOSTNAME_OLD.conf
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME_OLD-config.js
|
||||
fi
|
||||
|
||||
# apache2 config
|
||||
if [ ! -f /etc/apache2/sites-available/$JVB_HOSTNAME.conf ] ; then
|
||||
# when creating new config, make sure all needed modules are enabled
|
||||
a2enmod rewrite ssl headers proxy_http include
|
||||
cp /usr/share/doc/jitsi-meet-web/jitsi-meet.example-apache /etc/apache2/sites-available/$JVB_HOSTNAME.conf
|
||||
a2ensite $JVB_HOSTNAME.conf
|
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" /etc/apache2/sites-available/$JVB_HOSTNAME.conf
|
||||
fi
|
||||
|
||||
if [ "$CERT_CHOICE" = "$UPLOADED_CERT_CHOICE" ] ; then
|
||||
# replace self-signed certificate paths with user provided ones
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY | sed 's/\./\\\./g')
|
||||
CERT_KEY_ESC=$(echo $CERT_KEY_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/SSLCertificateKeyFile\ \/etc\/jitsi\/meet\/.*key/SSLCertificateKeyFile\ $CERT_KEY_ESC/g" \
|
||||
/etc/apache2/sites-available/$JVB_HOSTNAME.conf
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT | sed 's/\./\\\./g')
|
||||
CERT_CRT_ESC=$(echo $CERT_CRT_ESC | sed 's/\//\\\//g')
|
||||
sed -i "s/SSLCertificateFile\ \/etc\/jitsi\/meet\/.*crt/SSLCertificateFile\ $CERT_CRT_ESC/g" \
|
||||
/etc/apache2/sites-available/$JVB_HOSTNAME.conf
|
||||
fi
|
||||
|
||||
invoke-rc.d apache2 reload
|
||||
fi
|
||||
|
||||
# and we're done with debconf
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# postrm script for jitsi-meet
|
||||
# postrm script for jitsi-meet-web-config
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
@@ -27,6 +27,9 @@ case "$1" in
|
||||
if [ -x "/etc/init.d/nginx" ]; then
|
||||
invoke-rc.d nginx reload
|
||||
fi
|
||||
if [ -x "/etc/init.d/apache2" ]; then
|
||||
invoke-rc.d apache2 reload
|
||||
fi
|
||||
;;
|
||||
purge)
|
||||
db_get jitsi-meet/jvb-hostname
|
||||
@@ -35,9 +38,15 @@ case "$1" in
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME-config.js
|
||||
rm -f /etc/nginx/sites-available/$JVB_HOSTNAME.conf
|
||||
rm -f /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf
|
||||
rm -f /etc/apache2/sites-available/$JVB_HOSTNAME.conf
|
||||
rm -f /etc/apache2/sites-enabled/$JVB_HOSTNAME.conf
|
||||
rm -f /etc/jitsi/videobridge/$JVB_HOSTNAME.jks
|
||||
rm -f /etc/jitsi/videobridge/$JVB_HOSTNAME.p12
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME.key
|
||||
rm -f /etc/jitsi/meet/$JVB_HOSTNAME.crt
|
||||
fi
|
||||
# Clear the debconf variable
|
||||
db_purge
|
||||
;;
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
@@ -30,3 +30,8 @@ Type: boolean
|
||||
Default: false
|
||||
_Description: for internal use
|
||||
for internal use.
|
||||
|
||||
Template: jitsi-videobridge/jvb-hostname
|
||||
Type: string
|
||||
_Description: Hostname:
|
||||
The Jitsi Meet web config package needs the DNS hostname of your instance.
|
||||
@@ -1,4 +1,5 @@
|
||||
README.md
|
||||
doc/debian/jitsi-meet/jitsi-meet.example
|
||||
doc/debian/jitsi-meet/jitsi-meet.example-apache
|
||||
doc/debian/jitsi-meet/README
|
||||
config.js
|
||||
2
debian/po/POTFILES.in
vendored
2
debian/po/POTFILES.in
vendored
@@ -1 +1 @@
|
||||
[type: gettext/rfc822deb] jitsi-meet.templates
|
||||
[type: gettext/rfc822deb] jitsi-meet-web-config.templates
|
||||
|
||||
53
debian/po/templates.pot
vendored
53
debian/po/templates.pot
vendored
@@ -1,10 +1,14 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the jitsi-meet-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: jitsi-meet\n"
|
||||
"Report-Msgid-Bugs-To: jitsi-meet@packages.debian.org\n"
|
||||
"POT-Creation-Date: 2014-09-03 17:26+0200\n"
|
||||
"Project-Id-Version: jitsi-meet-web\n"
|
||||
"Report-Msgid-Bugs-To: jitsi-meet-web@packages.debian.org\n"
|
||||
"POT-Creation-Date: 2016-11-15 22:39+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -15,25 +19,25 @@ msgstr ""
|
||||
|
||||
#. Type: select
|
||||
#. Choices
|
||||
#: ../jitsi-meet.templates:1001
|
||||
#: ../jitsi-meet-web-config.templates:1001
|
||||
msgid "Self-signed certificate will be generated"
|
||||
msgstr ""
|
||||
|
||||
#. Type: select
|
||||
#. Choices
|
||||
#: ../jitsi-meet.templates:1001
|
||||
#: ../jitsi-meet-web-config.templates:1001
|
||||
msgid "A certificate is available and the files are uploaded on the server"
|
||||
msgstr ""
|
||||
|
||||
#. Type: select
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:1002
|
||||
#: ../jitsi-meet-web-config.templates:1002
|
||||
msgid "SSL certificate for the Jitsi Meet instance"
|
||||
msgstr ""
|
||||
|
||||
#. Type: select
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:1002
|
||||
#: ../jitsi-meet-web-config.templates:1002
|
||||
msgid ""
|
||||
"Jitsi Meet is best to be set up with an SSL certificate. Having no "
|
||||
"certificate, a self-signed one will be generated. Having a certificate "
|
||||
@@ -44,13 +48,13 @@ msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:2001
|
||||
#: ../jitsi-meet-web-config.templates:2001
|
||||
msgid "Full local server path to the SSL key file:"
|
||||
msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:2001
|
||||
#: ../jitsi-meet-web-config.templates:2001
|
||||
msgid ""
|
||||
"The full path to the SSL key file on the server. If it has not been "
|
||||
"uploaded, now is a good time to do so."
|
||||
@@ -58,13 +62,13 @@ msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:3001
|
||||
#: ../jitsi-meet-web-config.templates:3001
|
||||
msgid "Full local server path to the SSL certificate file:"
|
||||
msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:3001
|
||||
#: ../jitsi-meet-web-config.templates:3001
|
||||
msgid ""
|
||||
"The full path to the SSL certificate file on the server. If you haven't "
|
||||
"uploaded it, now is a good time to upload it in another console."
|
||||
@@ -72,27 +76,38 @@ msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:4001
|
||||
#: ../jitsi-meet-web-config.templates:4001
|
||||
msgid "The hostname of the current installation:"
|
||||
msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:4001
|
||||
#: ../jitsi-meet-web-config.templates:4001
|
||||
msgid ""
|
||||
"The value for the hostname that is set in Jitsi Videobridge installation."
|
||||
msgstr ""
|
||||
|
||||
|
||||
#. Type: string
|
||||
#. Type: boolean
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:5001
|
||||
#: ../jitsi-meet-web-config.templates:5001
|
||||
msgid "for internal use"
|
||||
msgstr ""
|
||||
|
||||
#. Type: boolean
|
||||
#. Description
|
||||
#: ../jitsi-meet-web-config.templates:5001
|
||||
msgid "for internal use."
|
||||
msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet.templates:5001
|
||||
msgid ""
|
||||
"Jitsi Videobridge installation can use its internal jetty to serve static meet pages."
|
||||
#: ../jitsi-meet-web-config.templates:6001
|
||||
msgid "Hostname:"
|
||||
msgstr ""
|
||||
|
||||
#. Type: string
|
||||
#. Description
|
||||
#: ../jitsi-meet-web-config.templates:6001
|
||||
msgid ""
|
||||
"The Jitsi Meet web config package needs the DNS hostname of your instance."
|
||||
msgstr ""
|
||||
|
||||
@@ -33,7 +33,7 @@ You can overwrite options set in config.js and interface_config.js. For example,
|
||||
```javascript
|
||||
var configOverwrite = {enableSimulcast: false};
|
||||
var interfaceConfigOverwrite = {filmStripOnly: true};
|
||||
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, true, configOverwrite, interfaceConfigOverwrite);
|
||||
var api = new JitsiMeetExternalAPI(domain, room, width, height, htmlElement, configOverwrite, interfaceConfigOverwrite);
|
||||
```
|
||||
|
||||
Controlling embedded Jitsi Meet Conference
|
||||
@@ -54,7 +54,7 @@ Currently we support the following commands:
|
||||
* **displayName** - sets the display name of the local participant. This command requires one argument -
|
||||
the new display name to be set
|
||||
```
|
||||
api.executeCommand('displayName', ['New Nickname']);
|
||||
api.executeCommand('displayName', 'New Nickname');
|
||||
```
|
||||
* **toggleAudio** - mutes / unmutes the audio for the local participant. No arguments are required.
|
||||
```
|
||||
|
||||
@@ -15,8 +15,8 @@ server {
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
|
||||
ssl_certificate /var/lib/prosody/jitsi-meet.example.com.crt;
|
||||
ssl_certificate_key /var/lib/prosody/jitsi-meet.example.com.key;
|
||||
ssl_certificate /etc/jitsi/meet/jitsi-meet.example.com.crt;
|
||||
ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key;
|
||||
|
||||
root /usr/share/jitsi-meet;
|
||||
index index.html index.htm;
|
||||
|
||||
43
doc/debian/jitsi-meet/jitsi-meet.example-apache
Normal file
43
doc/debian/jitsi-meet/jitsi-meet.example-apache
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName jitsi-meet.example.com
|
||||
Redirect permanent / https://jitsi-meet.example.com/
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
|
||||
ServerName jitsi-meet.example.com
|
||||
|
||||
SSLProtocol TLSv1 TLSv1.1 TLSv1.2
|
||||
SSLEngine on
|
||||
SSLProxyEngine on
|
||||
SSLCertificateFile /etc/jitsi/meet/jitsi-meet.example.com.crt
|
||||
SSLCertificateKeyFile /etc/jitsi/meet/jitsi-meet.example.com.key
|
||||
SSLCipherSuite "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL:!eNULL:!MEDIUM:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:!SEED"
|
||||
SSLHonorCipherOrder on
|
||||
Header set Strict-Transport-Security "max-age=31536000"
|
||||
|
||||
DocumentRoot "/usr/share/jitsi-meet"
|
||||
<Directory "/usr/share/jitsi-meet">
|
||||
Options Indexes MultiViews Includes FollowSymLinks
|
||||
AddOutputFilter Includes html
|
||||
AllowOverride All
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
Alias "/config.js" "/etc/jitsi/meet/jitsi-meet.example.com-config.js"
|
||||
<Location /config.js>
|
||||
Require all granted
|
||||
</Location>
|
||||
|
||||
ProxyPreserveHost on
|
||||
ProxyPass /http-bind http://localhost:5280/http-bind/
|
||||
ProxyPassReverse /http-bind http://localhost:5280/http-bind/
|
||||
|
||||
RewriteEngine on
|
||||
RewriteRule ^/([a-zA-Z0-9]+)$ /index.html
|
||||
</VirtualHost>
|
||||
139
index.html
139
index.html
@@ -14,6 +14,7 @@
|
||||
"utils.js",
|
||||
"do_external_connect.js",
|
||||
"interface_config.js",
|
||||
"logging_config.js",
|
||||
"lib-jitsi-meet.min.js",
|
||||
"app.bundle.min.js",
|
||||
"all.css"
|
||||
@@ -34,7 +35,7 @@
|
||||
window.removeEventListener(
|
||||
'error', loadErrHandler, true /* capture phase */);
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener(
|
||||
'error', loadErrHandler, true /* capture phase type of listener */);
|
||||
</script>
|
||||
@@ -50,141 +51,7 @@
|
||||
<!--#include virtual="plugin.head.html" -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="welcome_page">
|
||||
<div id="welcome_page_header">
|
||||
<a target="_new">
|
||||
<div class="watermark leftwatermark"></div>
|
||||
</a>
|
||||
<a target="_new">
|
||||
<div class="watermark rightwatermark"></div>
|
||||
</a>
|
||||
<a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
|
||||
|
||||
<div id="enter_room_container">
|
||||
<div id="enter_room_form" >
|
||||
<div id="domain_name"></div>
|
||||
<div id="enter_room">
|
||||
<input id="enter_room_field" type="text" autofocus/>
|
||||
<div class="icon-reload" id="reload_roomname"></div>
|
||||
<input id="enter_room_button" type="button" data-i18n="[value]welcomepage.go" value="GO" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="brand_header"></div>
|
||||
<input type='checkbox' name='checkbox' id="disable_welcome"/>
|
||||
<label for="disable_welcome" class="disable_welcome_position" data-i18n="welcomepage.disable"></label>
|
||||
<div id="header_text">
|
||||
<!--#include virtual="plugin.header.text.html" -->
|
||||
</div>
|
||||
</div>
|
||||
<div id="welcome_page_main">
|
||||
<div id="features">
|
||||
<div class="feature_row">
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature1.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature1.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature2.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature2.content">
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature3.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature3.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature4.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature4.content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_row">
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature5.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature5.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature6.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature6.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature7.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature7.content" data-i18n-options='{ "postProcess": "resolveAppName" }'></div>
|
||||
</div>
|
||||
<div class="feature_holder">
|
||||
<div class="feature_icon" data-i18n="welcomepage.feature8.title" ></div>
|
||||
<div class="feature_description" data-i18n="welcomepage.feature8.content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--#include virtual="plugin.welcomepage.footer.html" -->
|
||||
</div>
|
||||
<div id="videoconference_page">
|
||||
<div id="mainToolbarContainer">
|
||||
<div id="notice" class="notice" style="display: none">
|
||||
<span id="noticeText" class="noticeText"></span>
|
||||
</div>
|
||||
<div id="mainToolbar" class="toolbar"></div>
|
||||
</div>
|
||||
<div id="subject" class="hide"></div>
|
||||
|
||||
<div id="extendedToolbar" class="toolbar">
|
||||
<div id="extendedToolbarButtons"></div>
|
||||
|
||||
<a class="button icon-feedback" id="feedbackButton"></a>
|
||||
|
||||
<div id="sideToolbarContainer"></div>
|
||||
</div>
|
||||
<div id="videospace">
|
||||
<div id="largeVideoContainer" class="videocontainer">
|
||||
<div id="sharedVideo"><div id="sharedVideoIFrame"></div></div>
|
||||
<div id="etherpad"></div>
|
||||
<a target="_new"><div class="watermark leftwatermark"></div></a>
|
||||
<a target="_new"><div class="watermark rightwatermark"></div></a>
|
||||
<a class="poweredby" href="http://jitsi.org" target="_new">
|
||||
<span data-i18n="poweredby"></span> jitsi.org
|
||||
</a>
|
||||
<div id="dominantSpeaker">
|
||||
<div class="dynamic-shadow"></div>
|
||||
<img id="dominantSpeakerAvatar" src=""/>
|
||||
</div>
|
||||
<span id="remoteConnectionMessage"></span>
|
||||
<div id="largeVideoWrapper">
|
||||
<video id="largeVideo" muted="true" autoplay></video>
|
||||
</div>
|
||||
<span id="localConnectionMessage"></span>
|
||||
<span id="videoResolutionLabel" class="video-state-indicator moveToCorner">HD</span>
|
||||
<span id="recordingLabel" class="video-state-indicator centeredVideoLabel">
|
||||
<span id="recordingLabelText"></span>
|
||||
<img id="recordingSpinner" class="recordingSpinner" src="images/spin.svg"></img>
|
||||
</span>
|
||||
</div>
|
||||
<div class="filmstrip">
|
||||
<div class="filmstrip__videos" id="remoteVideos">
|
||||
<span id="localVideoContainer" class="videocontainer videocontainer_small">
|
||||
<div class="videocontainer__background"></div>
|
||||
<span id="localVideoWrapper">
|
||||
<!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
|
||||
</span>
|
||||
<audio id="localAudio" autoplay muted></audio>
|
||||
<div class="videocontainer__toolbar"></div>
|
||||
<div class="videocontainer__toptoolbar"></div>
|
||||
<div class="videocontainer__hoverOverlay"></div>
|
||||
</span>
|
||||
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
||||
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="react"></div>
|
||||
<div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
|
||||
<div class="content">
|
||||
<ul id="keyboard-shortcuts-list" class="shortcuts-list">
|
||||
|
||||
@@ -22,8 +22,6 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||
* If we should show authentication block in profile
|
||||
*/
|
||||
AUTHENTICATION_ENABLE: true,
|
||||
// the toolbar buttons line is intentionally left in one line, to be able
|
||||
// to easily override values or remove them using regex
|
||||
/**
|
||||
* The index of the splitter button in the main toolbar. The splitter
|
||||
* button is a button in the toolbar that will be applied a special styling
|
||||
|
||||
@@ -11,12 +11,17 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" userInteractionEnabled="NO" contentMode="center" fixedFrame="YES" image="LaunchScreen" translatesAutoresizingMaskIntoConstraints="NO" id="4B8-Xf-NDE">
|
||||
<imageView opaque="NO" userInteractionEnabled="NO" contentMode="center" image="LaunchScreen" translatesAutoresizingMaskIntoConstraints="NO" id="4B8-Xf-NDE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.090196078431372548" green="0.62745098039215685" blue="0.85882352941176465" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="4B8-Xf-NDE" secondAttribute="bottom" id="aFF-BR-glX"/>
|
||||
<constraint firstItem="4B8-Xf-NDE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="glR-YN-1GF"/>
|
||||
<constraint firstAttribute="trailing" secondItem="4B8-Xf-NDE" secondAttribute="trailing" id="tva-gl-jRX"/>
|
||||
<constraint firstItem="4B8-Xf-NDE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="yaV-1V-oEh"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 167 KiB |
@@ -36,6 +36,8 @@
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
{
|
||||
"appID": "BQNXB4G3KQ.org.jitsi.JitsiMeet.ios",
|
||||
"paths": [ "*" ]
|
||||
},
|
||||
{
|
||||
"appID": "UPXU4CQZ5P.com.atlassian.JitsiMeet.ios",
|
||||
"paths": [ "*" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
|
||||
B30EF2341DC0EEA500690F45 /* Embed Frameworks */,
|
||||
B3DBBAC41DC6A3BE001DA4DD /* ShellScript */,
|
||||
B35383AD1DDA0083008F406A /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -721,6 +722,19 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
|
||||
};
|
||||
B35383AD1DDA0083008F406A /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "APP_PATH=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\n\n# This script loops through the frameworks embedded in the application and\n# removes unused architectures.\nfind \"$APP_PATH\" -name '*.framework' -type d | while read -r FRAMEWORK\ndo\nFRAMEWORK_EXECUTABLE_NAME=$(defaults read \"$FRAMEWORK/Info.plist\" CFBundleExecutable)\nFRAMEWORK_EXECUTABLE_PATH=\"$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME\"\necho \"Executable is $FRAMEWORK_EXECUTABLE_PATH\"\n\nEXTRACTED_ARCHS=()\n\nfor ARCH in $ARCHS\ndo\necho \"Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME\"\nlipo -extract \"$ARCH\" \"$FRAMEWORK_EXECUTABLE_PATH\" -o \"$FRAMEWORK_EXECUTABLE_PATH-$ARCH\"\nEXTRACTED_ARCHS+=(\"$FRAMEWORK_EXECUTABLE_PATH-$ARCH\")\ndone\n\necho \"Merging extracted architectures: ${ARCHS}\"\nlipo -o \"$FRAMEWORK_EXECUTABLE_PATH-merged\" -create \"${EXTRACTED_ARCHS[@]}\"\nrm \"${EXTRACTED_ARCHS[@]}\"\n\necho \"Replacing original executable with thinned version\"\nrm \"$FRAMEWORK_EXECUTABLE_PATH\"\nmv \"$FRAMEWORK_EXECUTABLE_PATH-merged\" \"$FRAMEWORK_EXECUTABLE_PATH\"\n\ndone";
|
||||
};
|
||||
B3DBBAC41DC6A3BE001DA4DD /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -766,7 +780,6 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "jitsi-meet-react.entitlements";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEAD_CODE_STRIPPING = NO;
|
||||
ENABLE_BITCODE = NO;
|
||||
|
||||
@@ -79,6 +79,10 @@
|
||||
"policyText": " ",
|
||||
"title": "__app__ needs to use your microphone and camera."
|
||||
},
|
||||
"suspendedoverlay": {
|
||||
"title": "Your video call was interrupted, because this computer went to sleep.",
|
||||
"rejoinKeyTitle": "Rejoin"
|
||||
},
|
||||
"toolbar": {
|
||||
"mute": "Mute / Unmute",
|
||||
"videomute": "Start / Stop camera",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global APP, getConfigParamsFromUrl */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Implements API class that communicates with external api class
|
||||
* and provides interface to access Jitsi Meet features by external
|
||||
@@ -131,13 +133,13 @@ function onSystemMessage(message) {
|
||||
switch (message.type) {
|
||||
case "eventStatus":
|
||||
if(!message.name || !message.value) {
|
||||
console.warn("Unknown system message format", message);
|
||||
logger.warn("Unknown system message format", message);
|
||||
break;
|
||||
}
|
||||
events[message.name] = message.value;
|
||||
break;
|
||||
default:
|
||||
console.warn("Unknown system message type", message);
|
||||
logger.warn("Unknown system message type", message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
modules/API/external/external_api.js
vendored
10
modules/API/external/external_api.js
vendored
@@ -1,3 +1,5 @@
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Implements API class that embeds Jitsi Meet in external applications.
|
||||
*/
|
||||
@@ -72,7 +74,7 @@ function sendMessage(postis, object) {
|
||||
*/
|
||||
function changeEventStatus(postis, event, status) {
|
||||
if(!(event in events)) {
|
||||
console.error("Not supported event name.");
|
||||
logger.error("Not supported event name.");
|
||||
return;
|
||||
}
|
||||
sendMessage(postis, {
|
||||
@@ -174,7 +176,7 @@ function JitsiMeetExternalAPI(domain, room_name, width, height, parentNode,
|
||||
*/
|
||||
JitsiMeetExternalAPI.prototype.executeCommand = function(name, argumentsList) {
|
||||
if(!(name in commands)) {
|
||||
console.error("Not supported command name.");
|
||||
logger.error("Not supported command name.");
|
||||
return;
|
||||
}
|
||||
var argumentsArray = argumentsList;
|
||||
@@ -306,7 +308,7 @@ JitsiMeetExternalAPI.prototype.addEventListeners = function(object) {
|
||||
*/
|
||||
JitsiMeetExternalAPI.prototype.addEventListener = function(event, listener) {
|
||||
if(!(event in events)) {
|
||||
console.error("Not supported event name.");
|
||||
logger.error("Not supported event name.");
|
||||
return;
|
||||
}
|
||||
// We cannot remove listeners from postis that's why we are handling the
|
||||
@@ -328,7 +330,7 @@ JitsiMeetExternalAPI.prototype.addEventListener = function(event, listener) {
|
||||
JitsiMeetExternalAPI.prototype.removeEventListener = function(event) {
|
||||
if(!(event in this.eventHandlers))
|
||||
{
|
||||
console.error("The event " + event + " is not registered.");
|
||||
logger.error("The event " + event + " is not registered.");
|
||||
return;
|
||||
}
|
||||
delete this.eventHandlers[event];
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import UIEvents from '../service/UI/UIEvents';
|
||||
import VideoLayout from './UI/videolayout/VideoLayout';
|
||||
@@ -308,7 +309,7 @@ class FollowMe {
|
||||
|
||||
if (!this._conference.isParticipantModerator(id))
|
||||
{
|
||||
console.warn('Received follow-me command ' +
|
||||
logger.warn('Received follow-me command ' +
|
||||
'not from moderator');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global APP, JitsiMeetJS, $, config, interfaceConfig, toastr */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
var UI = {};
|
||||
|
||||
import Chat from "./side_pannels/chat/Chat";
|
||||
@@ -16,6 +18,7 @@ import GumPermissionsOverlay
|
||||
from './gum_overlay/UserMediaPermissionsGuidanceOverlay';
|
||||
|
||||
import PageReloadOverlay from './reload_overlay/PageReloadOverlay';
|
||||
import SuspendedOverlay from './suspended_overlay/SuspendedOverlay';
|
||||
import VideoLayout from "./videolayout/VideoLayout";
|
||||
import FilmStrip from "./videolayout/FilmStrip";
|
||||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
||||
@@ -30,7 +33,7 @@ var EventEmitter = require("events");
|
||||
UI.messageHandler = require("./util/MessageHandler");
|
||||
var messageHandler = UI.messageHandler;
|
||||
var JitsiPopover = require("./util/JitsiPopover");
|
||||
var Feedback = require("./feedback/Feedback");
|
||||
import Feedback from "./feedback/Feedback";
|
||||
import FollowMe from "../FollowMe";
|
||||
|
||||
var eventEmitter = new EventEmitter();
|
||||
@@ -79,12 +82,11 @@ JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[TrackErrors.NO_DATA_FROM_SOURCE]
|
||||
function promptDisplayName() {
|
||||
let labelKey = 'dialog.enterDisplayName';
|
||||
let message = (
|
||||
`<div class="input-control">
|
||||
<label data-i18n="${labelKey}" class="input-control__label"></label>
|
||||
`<div class="form-control">
|
||||
<label data-i18n="${labelKey}" class="form-control__label"></label>
|
||||
<input name="displayName" type="text"
|
||||
data-i18n="[placeholder]defaultNickname"
|
||||
class="input-control__input"
|
||||
autofocus>
|
||||
class="input-control" autofocus>
|
||||
</div>`
|
||||
);
|
||||
|
||||
@@ -443,10 +445,10 @@ UI.start = function () {
|
||||
// Display notice message at the top of the toolbar
|
||||
if (config.noticeMessage) {
|
||||
$('#noticeText').text(config.noticeMessage);
|
||||
$('#notice').css({display: 'block'});
|
||||
UIUtil.setVisible('notice', true);
|
||||
}
|
||||
} else {
|
||||
$("#mainToolbarContainer").css("display", "none");
|
||||
UIUtil.setVisible('mainToolbarContainer', false);
|
||||
FilmStrip.setupFilmStripOnly();
|
||||
messageHandler.enableNotifications(false);
|
||||
JitsiPopover.enabled = false;
|
||||
@@ -474,7 +476,9 @@ UI.start = function () {
|
||||
"hideEasing": "linear",
|
||||
"showMethod": "fadeIn",
|
||||
"hideMethod": "fadeOut",
|
||||
"newestOnTop": false
|
||||
"newestOnTop": false,
|
||||
// this is the default toastr close button html, just adds tabIndex
|
||||
"closeHtml": '<button type="button" tabIndex="-1">×</button>'
|
||||
};
|
||||
|
||||
}
|
||||
@@ -501,7 +505,7 @@ UI.addLocalStream = function (track) {
|
||||
VideoLayout.changeLocalVideo(track);
|
||||
break;
|
||||
default:
|
||||
console.error("Unknown stream type: " + track.getType());
|
||||
logger.error("Unknown stream type: " + track.getType());
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -539,7 +543,7 @@ UI.initEtherpad = function (name) {
|
||||
if (etherpadManager || !config.etherpad_base || !name) {
|
||||
return;
|
||||
}
|
||||
console.log('Etherpad is enabled');
|
||||
logger.log('Etherpad is enabled');
|
||||
etherpadManager
|
||||
= new EtherpadManager(config.etherpad_base, name, eventEmitter);
|
||||
Toolbar.showEtherpadButton();
|
||||
@@ -737,13 +741,15 @@ UI.connectionIndicatorShowMore = function(id) {
|
||||
|
||||
// FIXME check if someone user this
|
||||
UI.showLoginPopup = function(callback) {
|
||||
console.log('password is required');
|
||||
logger.log('password is required');
|
||||
|
||||
let message = (
|
||||
`<input name="username" type="text"
|
||||
placeholder="user@domain.net" autofocus>
|
||||
placeholder="user@domain.net"
|
||||
class="input-control" autofocus>
|
||||
<input name="password" type="password"
|
||||
data-i18n="[placeholder]dialog.userPassword"
|
||||
class="input-control"
|
||||
placeholder="user password">`
|
||||
);
|
||||
|
||||
@@ -1086,10 +1092,16 @@ UI.notifyFocusDisconnected = function (focus, retrySec) {
|
||||
/**
|
||||
* Notify the user that the video conferencing service is badly broken and
|
||||
* the page should be reloaded.
|
||||
*
|
||||
* @param {boolean} isNetworkFailure <tt>true</tt> indicates that it's caused by
|
||||
* network related failure or <tt>false</tt> when it's the infrastructure.
|
||||
* @param {string} a label string identifying the reason for the page reload
|
||||
* which will be included in details of the log event.
|
||||
*/
|
||||
UI.showPageReloadOverlay = function () {
|
||||
UI.showPageReloadOverlay = function (isNetworkFailure, reason) {
|
||||
// Reload the page after 10 - 30 seconds
|
||||
PageReloadOverlay.show(10 + RandomUtil.randomInt(0, 20));
|
||||
PageReloadOverlay.show(
|
||||
10 + RandomUtil.randomInt(0, 20), isNetworkFailure, reason);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1101,13 +1113,13 @@ UI.updateAuthInfo = function (isAuthEnabled, login) {
|
||||
let showAuth = isAuthEnabled && UIUtil.isAuthenticationEnabled();
|
||||
let loggedIn = !!login;
|
||||
|
||||
Toolbar.showAuthenticateButton(showAuth);
|
||||
Profile.showAuthenticationButtons(showAuth);
|
||||
|
||||
if (showAuth) {
|
||||
Toolbar.setAuthenticatedIdentity(login);
|
||||
Profile.setAuthenticatedIdentity(login);
|
||||
|
||||
Toolbar.showLoginButton(!loggedIn);
|
||||
Toolbar.showLogoutButton(loggedIn);
|
||||
Profile.showLoginButton(!loggedIn);
|
||||
Profile.showLogoutButton(loggedIn);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1177,7 +1189,7 @@ UI.getLargeVideo = function () {
|
||||
UI.showExtensionRequiredDialog = function (url) {
|
||||
messageHandler.openMessageDialog(
|
||||
"dialog.extensionRequired",
|
||||
"dialog.firefoxExtensionPrompt",
|
||||
"[html]dialog.firefoxExtensionPrompt",
|
||||
{url: url});
|
||||
};
|
||||
|
||||
@@ -1399,12 +1411,14 @@ UI.hideRingOverLay = function () {
|
||||
|
||||
/**
|
||||
* Indicates if any the "top" overlays are currently visible. The check includes
|
||||
* the call overlay, GUM permissions overlay and a page reload overlay.
|
||||
* the call overlay, suspended overlay, GUM permissions overlay
|
||||
* and a page reload overlay.
|
||||
*
|
||||
* @returns {*|boolean} {true} if the overlay is visible, {false} otherwise
|
||||
*/
|
||||
UI.isOverlayVisible = function () {
|
||||
return RingOverlay.isVisible()
|
||||
|| SuspendedOverlay.isVisible()
|
||||
|| PageReloadOverlay.isVisible()
|
||||
|| GumPermissionsOverlay.isVisible();
|
||||
};
|
||||
@@ -1427,6 +1441,13 @@ UI.showUserMediaPermissionsGuidanceOverlay = function (browser) {
|
||||
GumPermissionsOverlay.show(browser);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows suspended overlay with a button to rejoin conference.
|
||||
*/
|
||||
UI.showSuspendedOverlay = function () {
|
||||
SuspendedOverlay.show();
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides browser-specific overlay with guidance how to proceed with gUM prompt.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global APP, config, JitsiMeetJS, Promise */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import LoginDialog from './LoginDialog';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
@@ -74,13 +75,13 @@ function redirectToTokenAuthService(roomName) {
|
||||
function initJWTTokenListener(room) {
|
||||
var listener = function (event) {
|
||||
if (externalAuthWindow !== event.source) {
|
||||
console.warn("Ignored message not coming " +
|
||||
logger.warn("Ignored message not coming " +
|
||||
"from external authnetication window");
|
||||
return;
|
||||
}
|
||||
if (event.data && event.data.jwtToken) {
|
||||
config.token = event.data.jwtToken;
|
||||
console.info("Received JWT token:", config.token);
|
||||
logger.info("Received JWT token:", config.token);
|
||||
var roomName = room.getName();
|
||||
openConnection({retry: false, roomName: roomName })
|
||||
.then(function (connection) {
|
||||
@@ -97,10 +98,10 @@ function initJWTTokenListener(room) {
|
||||
// to upgrade user's role
|
||||
room.room.moderator.authenticate()
|
||||
.then(function () {
|
||||
console.info("User role upgrade done !");
|
||||
logger.info("User role upgrade done !");
|
||||
unregister();
|
||||
}).catch(function (err, errCode) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Authentication failed: ", err, errCode);
|
||||
unregister();
|
||||
}
|
||||
@@ -108,13 +109,13 @@ function initJWTTokenListener(room) {
|
||||
}).catch(function (error, code) {
|
||||
unregister();
|
||||
connection.disconnect();
|
||||
console.error(
|
||||
logger.error(
|
||||
'Authentication failed on the new connection',
|
||||
error, code);
|
||||
});
|
||||
}, function (err) {
|
||||
unregister();
|
||||
console.error("Failed to open new connection", err);
|
||||
logger.error("Failed to open new connection", err);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -161,7 +162,7 @@ function doXmppAuth (room, lockPassword) {
|
||||
}).catch(function (error, code) {
|
||||
connection.disconnect();
|
||||
|
||||
console.error('Auth on the fly failed', error);
|
||||
logger.error('Auth on the fly failed', error);
|
||||
|
||||
loginDialog.displayError(
|
||||
'connection.GET_SESSION_ID_ERROR', {code: code});
|
||||
|
||||
@@ -11,10 +11,10 @@ function getPasswordInputHtml() {
|
||||
|
||||
return `
|
||||
<input name="username" type="text"
|
||||
class="input-control__input"
|
||||
class="input-control"
|
||||
placeholder=${placeholder} autofocus>
|
||||
<input name="password" type="password"
|
||||
class="input-control__input"
|
||||
class="input-control"
|
||||
data-i18n="[placeholder]dialog.userPassword">`;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ export default {
|
||||
*/
|
||||
showAuthRequiredDialog: function (roomName, onAuthNow) {
|
||||
var msg = APP.translation.generateTranslationHTML(
|
||||
"dialog.WaitForHostMsg", {room: roomName}
|
||||
"[html]dialog.WaitForHostMsg", {room: roomName}
|
||||
);
|
||||
|
||||
var buttonTxt = APP.translation.generateTranslationHTML(
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
/*
|
||||
* Adorable Avatars service used at the end of this file is released under the
|
||||
* terms of the MIT License.
|
||||
*
|
||||
* Copyright (c) 2014 Adorable IO LLC
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* global MD5, config, interfaceConfig, APP */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
let users = {};
|
||||
|
||||
@@ -87,7 +111,7 @@ export default {
|
||||
let random = !avatarId || avatarId.indexOf('@') < 0;
|
||||
|
||||
if (!avatarId) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`No avatar stored yet for ${userId} - using ID as avatar ID`);
|
||||
avatarId = userId;
|
||||
}
|
||||
@@ -105,8 +129,8 @@ export default {
|
||||
urlSuf = interfaceConfig.RANDOM_AVATAR_URL_SUFFIX;
|
||||
}
|
||||
else {
|
||||
urlPref = 'https://robohash.org/';
|
||||
urlSuf = ".png?size=200x200";
|
||||
urlPref = 'https://api.adorable.io/avatars/200/';
|
||||
urlSuf = ".png";
|
||||
}
|
||||
|
||||
return urlPref + avatarId + urlSuf;
|
||||
|
||||
@@ -1,36 +1,12 @@
|
||||
/* global $, APP, JitsiMeetJS */
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import FeedbackWindow from "./FeedbackWindow";
|
||||
|
||||
/**
|
||||
* Shows / hides the feedback button.
|
||||
* @private
|
||||
*/
|
||||
function _toggleFeedbackIcon() {
|
||||
$('#feedbackButtonDiv').toggleClass("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows / hides the feedback button.
|
||||
* @param {show} set to {true} to show the feedback button or to {false}
|
||||
* to hide it
|
||||
* @private
|
||||
*/
|
||||
function _showFeedbackButton (show) {
|
||||
var feedbackButton = $("#feedbackButtonDiv");
|
||||
|
||||
if (show)
|
||||
feedbackButton.css("display", "block");
|
||||
else
|
||||
feedbackButton.css("display", "none");
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines all methods in connection to the Feedback window.
|
||||
*
|
||||
* @type {{openFeedbackWindow: Function}}
|
||||
*/
|
||||
var Feedback = {
|
||||
const Feedback = {
|
||||
|
||||
/**
|
||||
* Initialise the Feedback functionality.
|
||||
@@ -47,24 +23,15 @@ var Feedback = {
|
||||
if (typeof this.enabled == "undefined")
|
||||
this.enabled = true;
|
||||
|
||||
_showFeedbackButton(this.enabled);
|
||||
|
||||
this.window = new FeedbackWindow();
|
||||
this.emitter = emitter;
|
||||
|
||||
$("#feedbackButton").click(Feedback.openFeedbackWindow);
|
||||
|
||||
// Show / hide the feedback button whenever the film strip is
|
||||
// shown / hidden.
|
||||
emitter.addListener(UIEvents.TOGGLE_FILM_STRIP, function () {
|
||||
_toggleFeedbackIcon();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Enables/ disabled the feedback feature.
|
||||
*/
|
||||
enableFeedback: function (enable) {
|
||||
if (this.enabled !== enable)
|
||||
_showFeedbackButton(enable);
|
||||
this.enabled = enable;
|
||||
},
|
||||
|
||||
@@ -125,4 +92,4 @@ var Feedback = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Feedback;
|
||||
export default Feedback;
|
||||
|
||||
@@ -66,7 +66,7 @@ function createRateFeedbackHTML() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="details">
|
||||
<textarea id="feedbackTextArea" class="input-control__input"
|
||||
<textarea id="feedbackTextArea" class="input-control"
|
||||
data-i18n="[placeholder]dialog.feedbackHelp"></textarea>
|
||||
</div>
|
||||
</form>`;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global JitsiMeetJS, APP */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import InviteDialogView from './InviteDialogView';
|
||||
import createRoomLocker from './RoomLocker';
|
||||
@@ -28,7 +29,7 @@ class Invite {
|
||||
this.conference.on(ConferenceEvents.LOCK_STATE_CHANGED,
|
||||
(locked, error) => {
|
||||
|
||||
console.log("Received channel password lock change: ", locked,
|
||||
logger.log("Received channel password lock change: ", locked,
|
||||
error);
|
||||
|
||||
if (!locked) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global $, APP, JitsiMeetJS */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Substate for password
|
||||
@@ -120,20 +121,20 @@ export default class InviteDialogView {
|
||||
getShareLinkBlock() {
|
||||
let classes = 'button-control button-control_light copyInviteLink';
|
||||
return (
|
||||
`<div class="input-control">
|
||||
<label class="input-control__label" for="inviteLinkRef"
|
||||
`<div class="form-control">
|
||||
<label class="form-control__label" for="inviteLinkRef"
|
||||
data-i18n="${this.dialog.titleKey}"></label>
|
||||
<div class="input-control__container">
|
||||
<input class="input-control__input inviteLink"
|
||||
<div class="form-control__container">
|
||||
<input class="input-control inviteLink"
|
||||
id="inviteLinkRef" type="text"
|
||||
${this.inviteAttributes} readonly>
|
||||
<button data-i18n="dialog.copy" class="${classes}"></button>
|
||||
</div>
|
||||
<p class="input-control__hint ${this.lockHint}">
|
||||
<p class="form-control__hint ${this.lockHint}">
|
||||
<span class="icon-security-locked"></span>
|
||||
<span data-i18n="dialog.roomLocked"></span>
|
||||
</p>
|
||||
<p class="input-control__hint ${this.unlockHint}">
|
||||
<p class="form-control__hint ${this.unlockHint}">
|
||||
<span class="icon-security"></span>
|
||||
<span data-i18n="roomUnlocked"></span>
|
||||
</p>
|
||||
@@ -150,12 +151,13 @@ export default class InviteDialogView {
|
||||
|
||||
if (this.model.isModerator) {
|
||||
html = (`
|
||||
<div class="input-control">
|
||||
<label class="input-control__label"
|
||||
<div class="form-control">
|
||||
<label class="form-control__label"
|
||||
for="newPasswordInput" data-i18n="dialog.addPassword">
|
||||
</label>
|
||||
<div class="input-control__container">
|
||||
<input class="input-control__input" id="newPasswordInput"
|
||||
<div class="form-control__container">
|
||||
<input class="input-control"
|
||||
id="newPasswordInput"
|
||||
type="text"
|
||||
data-i18n="[placeholder]dialog.createPassword">
|
||||
<button id="addPasswordBtn" id="inviteDialogAddPassword"
|
||||
@@ -182,19 +184,19 @@ export default class InviteDialogView {
|
||||
|
||||
if (isModerator) {
|
||||
return (`
|
||||
<div class="input-control">
|
||||
<label class="input-control__label"
|
||||
<div class="form-control">
|
||||
<label class="form-control__label"
|
||||
data-i18n="dialog.passwordLabel"></label>
|
||||
<div class="input-control__container">
|
||||
<div class="form-control__container">
|
||||
<p>
|
||||
<span class="input-control__text"
|
||||
<span class="form-control__text"
|
||||
data-i18n="dialog.currentPassword"></span>
|
||||
<span id="inviteDialogPassword"
|
||||
class="input-control__em">
|
||||
class="form-control__em">
|
||||
${password}
|
||||
</span>
|
||||
</p>
|
||||
<a class="link input-control__right"
|
||||
<a class="link form-control__right"
|
||||
id="inviteDialogRemovePassword"
|
||||
data-i18n="dialog.removePassword"></a>
|
||||
</div>
|
||||
@@ -202,7 +204,7 @@ export default class InviteDialogView {
|
||||
`);
|
||||
} else {
|
||||
return (`
|
||||
<div class="input-control">
|
||||
<div class="form-control">
|
||||
<p>A participant protected this call with a password.</p>
|
||||
</div>
|
||||
`);
|
||||
@@ -311,7 +313,7 @@ export default class InviteDialogView {
|
||||
this.blur();
|
||||
}
|
||||
catch (err) {
|
||||
console.error('error when copy the text');
|
||||
logger.error('error when copy the text');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,13 +33,14 @@ export default class RequirePasswordDialog {
|
||||
*/
|
||||
_getBodyMessage() {
|
||||
return (
|
||||
`<div class="input-control">
|
||||
`<div class="form-control">
|
||||
<label class="input-control__label"
|
||||
data-i18n="${this.labelKey}"></label>
|
||||
<input class="input-control__input" name="lockKey" type="text"
|
||||
<input class="input-control__input input-control"
|
||||
name="lockKey" type="text"
|
||||
data-i18n="[placeholder]dialog.password"
|
||||
autofocus id="${this.inputId}">
|
||||
<p class="input-control__hint input-control__hint_error hide"
|
||||
<p class="form-control__hint form-control__hint_error hide"
|
||||
id="${this.errorId}"
|
||||
data-i18n="${this.errorKey}"></p>
|
||||
</div>`
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global APP, JitsiMeetJS */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import RequirePasswordDialog from './RequirePasswordDialog';
|
||||
|
||||
/**
|
||||
@@ -6,7 +8,7 @@ import RequirePasswordDialog from './RequirePasswordDialog';
|
||||
* because server doesn't support that.
|
||||
*/
|
||||
function notifyPasswordNotSupported () {
|
||||
console.warn('room passwords not supported');
|
||||
logger.warn('room passwords not supported');
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.warning", "dialog.passwordNotSupported");
|
||||
}
|
||||
@@ -16,7 +18,7 @@ function notifyPasswordNotSupported () {
|
||||
* @param {Error} err error
|
||||
*/
|
||||
function notifyPasswordFailed(err) {
|
||||
console.warn('setting password failed', err);
|
||||
logger.warn('setting password failed', err);
|
||||
APP.UI.messageHandler.showError(
|
||||
"dialog.lockTitle", "dialog.lockMessage");
|
||||
}
|
||||
@@ -64,7 +66,7 @@ export default function createRoomLocker (room) {
|
||||
if (!password)
|
||||
lockedElsewhere = false;
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
logger.error(err);
|
||||
if (err === ConferenceErrors.PASSWORD_NOT_SUPPORTED) {
|
||||
notifyPasswordNotSupported();
|
||||
} else {
|
||||
@@ -113,7 +115,7 @@ export default function createRoomLocker (room) {
|
||||
// pass stays between attempts
|
||||
password = null;
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
logger.error(reason);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import VideoLayout from '../videolayout/VideoLayout';
|
||||
@@ -55,7 +57,8 @@ function _requestLiveStreamId() {
|
||||
state0: {
|
||||
titleKey: "dialog.liveStreaming",
|
||||
html:
|
||||
`<input name="streamId" type="text"
|
||||
`<input class="input-control"
|
||||
name="streamId" type="text"
|
||||
data-i18n="[placeholder]dialog.streamKey"
|
||||
autofocus>`,
|
||||
persistent: false,
|
||||
@@ -123,6 +126,7 @@ function _requestRecordingToken () {
|
||||
let messageString = (
|
||||
`<input name="recordingToken" type="text"
|
||||
data-i18n="[placeholder]dialog.token"
|
||||
class="input-control"
|
||||
autofocus>`
|
||||
);
|
||||
return new Promise(function (resolve, reject) {
|
||||
@@ -325,7 +329,7 @@ var Recording = {
|
||||
}).catch(
|
||||
reason => {
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
logger.error(reason);
|
||||
else
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
'recording.canceled');
|
||||
@@ -348,7 +352,7 @@ var Recording = {
|
||||
}).catch(
|
||||
reason => {
|
||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
||||
console.error(reason);
|
||||
logger.error(reason);
|
||||
else
|
||||
JitsiMeetJS.analytics.sendEvent(
|
||||
'recording.canceled');
|
||||
@@ -387,11 +391,10 @@ var Recording = {
|
||||
* @param show {true} to show the recording button, {false} to hide it
|
||||
*/
|
||||
showRecordingButton (show) {
|
||||
if (_isRecordingButtonEnabled() && show) {
|
||||
$('#toolbar_button_record').css({display: "inline-block"});
|
||||
} else {
|
||||
$('#toolbar_button_record').css({display: "none"});
|
||||
}
|
||||
let shouldShow = show && _isRecordingButtonEnabled();
|
||||
let id = 'toolbar_button_record';
|
||||
|
||||
UIUtil.setVisible(id, shouldShow);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -474,10 +477,9 @@ var Recording = {
|
||||
labelSelector.css({display: "inline-block"});
|
||||
|
||||
// Recording spinner
|
||||
if (recordingState === Status.RETRYING)
|
||||
$("#recordingSpinner").show();
|
||||
else
|
||||
$("#recordingSpinner").hide();
|
||||
let spinnerId = 'recordingSpinner';
|
||||
UIUtil.setVisible(
|
||||
spinnerId, recordingState === Status.RETRYING);
|
||||
},
|
||||
// checks whether recording is enabled and whether we have params
|
||||
// to start automatically recording
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global $, APP, AJS */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import Overlay from '../overlay/Overlay';
|
||||
|
||||
@@ -31,20 +32,22 @@ class PageReloadOverlayImpl extends Overlay{
|
||||
* @override
|
||||
*/
|
||||
_buildOverlayContent() {
|
||||
return `
|
||||
<span data-i18n='dialog.conferenceReloadTitle'
|
||||
class='reload_overlay_title'></span>
|
||||
<span data-i18n='dialog.conferenceReloadMsg'
|
||||
class='reload_overlay_msg'></span>
|
||||
<div>
|
||||
<div id='reloadProgressBar' class="aui-progress-indicator">
|
||||
<span class="aui-progress-indicator-value"></span>
|
||||
</div>
|
||||
<span id='reloadSecRemaining'
|
||||
data-i18n="dialog.conferenceReloadTimeLeft"
|
||||
class='reload_overlay_msg'>
|
||||
</span>
|
||||
</div>`;
|
||||
return `<div class="inlay">
|
||||
<span data-i18n='dialog.conferenceReloadTitle'
|
||||
class='reload_overlay_title'></span>
|
||||
<span data-i18n='dialog.conferenceReloadMsg'
|
||||
class='reload_overlay_msg'></span>
|
||||
<div>
|
||||
<div id='reloadProgressBar'
|
||||
class="aui-progress-indicator">
|
||||
<span class="aui-progress-indicator-value"></span>
|
||||
</div>
|
||||
<span id='reloadSecRemaining'
|
||||
data-i18n="dialog.conferenceReloadTimeLeft"
|
||||
class='reload_overlay_msg'>
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +85,7 @@ class PageReloadOverlayImpl extends Overlay{
|
||||
}
|
||||
}.bind(this), 1000);
|
||||
|
||||
console.info(
|
||||
logger.info(
|
||||
"The conference will be reloaded after "
|
||||
+ this.timeLeft + " seconds.");
|
||||
}
|
||||
@@ -110,8 +113,13 @@ export default {
|
||||
*
|
||||
* @param {number} timeoutSeconds how many seconds before the conference
|
||||
* reload will happen.
|
||||
* @param {boolean} isNetworkFailure <tt>true</tt> indicates that it's
|
||||
* caused by network related failure or <tt>false</tt> when it's
|
||||
* the infrastructure.
|
||||
* @param {string} reason a label string identifying the reason for the page
|
||||
* reload which will be included in details of the log event
|
||||
*/
|
||||
show(timeoutSeconds) {
|
||||
show(timeoutSeconds, isNetworkFailure, reason) {
|
||||
|
||||
if (!overlay) {
|
||||
overlay = new PageReloadOverlayImpl(timeoutSeconds);
|
||||
@@ -121,7 +129,8 @@ export default {
|
||||
// FIXME (CallStats - issue) this event will not make it to
|
||||
// the CallStats, because the log queue is not flushed, before
|
||||
// "fabric terminated" is sent to the backed
|
||||
APP.conference.logEvent('page.reload');
|
||||
APP.conference.logEvent(
|
||||
'page.reload', undefined /* value */, reason /* label */);
|
||||
}
|
||||
overlay.show();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* global $, APP, YT, onPlayerReady, onPlayerStateChange, onPlayerError,
|
||||
JitsiMeetJS */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
@@ -75,7 +76,7 @@ export default class SharedVideoManager {
|
||||
JitsiMeetJS.analytics.sendEvent('sharedvideo.started');
|
||||
},
|
||||
err => {
|
||||
console.log('SHARED VIDEO CANCELED', err);
|
||||
logger.log('SHARED VIDEO CANCELED', err);
|
||||
JitsiMeetJS.analytics.sendEvent('sharedvideo.canceled');
|
||||
}
|
||||
);
|
||||
@@ -84,6 +85,14 @@ export default class SharedVideoManager {
|
||||
|
||||
if(APP.conference.isLocalId(this.from)) {
|
||||
showStopVideoPropmpt().then(() => {
|
||||
// make sure we stop updates for playing before we send stop
|
||||
// if we stop it after receiving self presence, we can end
|
||||
// up sending stop playing, and on the other end it will not
|
||||
// stop
|
||||
if(this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
this.emitter.emit(
|
||||
UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop');
|
||||
JitsiMeetJS.analytics.sendEvent('sharedvideo.stoped');
|
||||
@@ -269,7 +278,7 @@ export default class SharedVideoManager {
|
||||
};
|
||||
|
||||
window.onPlayerError = function(event) {
|
||||
console.error("Error in the player:", event.data);
|
||||
logger.error("Error in the player:", event.data);
|
||||
// store the error player, so we can remove it
|
||||
self.errorInPlayer = event.target;
|
||||
};
|
||||
@@ -305,7 +314,7 @@ export default class SharedVideoManager {
|
||||
&& player.getVolume() != attributes.volume) {
|
||||
|
||||
player.setVolume(attributes.volume);
|
||||
console.info("Player change of volume:" + attributes.volume);
|
||||
logger.info("Player change of volume:" + attributes.volume);
|
||||
this.showSharedVideoMutedPopup(false);
|
||||
}
|
||||
|
||||
@@ -329,7 +338,7 @@ export default class SharedVideoManager {
|
||||
processTime (player, attributes, forceSeek)
|
||||
{
|
||||
if(forceSeek) {
|
||||
console.info("Player seekTo:", attributes.time);
|
||||
logger.info("Player seekTo:", attributes.time);
|
||||
player.seekTo(attributes.time);
|
||||
return;
|
||||
}
|
||||
@@ -341,7 +350,7 @@ export default class SharedVideoManager {
|
||||
// if we drift more than the interval for checking
|
||||
// sync, the interval is in milliseconds
|
||||
if(diff > updateInterval/1000) {
|
||||
console.info("Player seekTo:", attributes.time,
|
||||
logger.info("Player seekTo:", attributes.time,
|
||||
" current time is:", currentPosition, " diff:", diff);
|
||||
player.seekTo(attributes.time);
|
||||
}
|
||||
@@ -423,11 +432,6 @@ export default class SharedVideoManager {
|
||||
}
|
||||
}
|
||||
|
||||
if(this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
}
|
||||
|
||||
this.emitter.removeListener(UIEvents.AUDIO_MUTED,
|
||||
this.localAudioMutedListener);
|
||||
this.localAudioMutedListener = null;
|
||||
@@ -666,7 +670,7 @@ SharedVideoThumb.prototype.videoClick = function () {
|
||||
* Removes RemoteVideo from the page.
|
||||
*/
|
||||
SharedVideoThumb.prototype.remove = function () {
|
||||
console.log("Remove shared video thumb", this.id);
|
||||
logger.log("Remove shared video thumb", this.id);
|
||||
|
||||
// Make sure that the large video is updated if are removing its
|
||||
// corresponding small video.
|
||||
@@ -683,7 +687,7 @@ SharedVideoThumb.prototype.remove = function () {
|
||||
*/
|
||||
SharedVideoThumb.prototype.setDisplayName = function(displayName) {
|
||||
if (!this.container) {
|
||||
console.warn( "Unable to set displayName - " + this.videoSpanId +
|
||||
logger.warn( "Unable to set displayName - " + this.videoSpanId +
|
||||
" does not exist");
|
||||
return;
|
||||
}
|
||||
@@ -762,6 +766,7 @@ function requestVideoLink() {
|
||||
titleKey: "dialog.shareVideoTitle",
|
||||
html: `
|
||||
<input name="sharedVideoUrl" type="text"
|
||||
class="input-control"
|
||||
data-i18n="[placeholder]defaultLink"
|
||||
autofocus>`,
|
||||
persistent: false,
|
||||
|
||||
@@ -109,6 +109,16 @@ const SideContainerToggler = {
|
||||
* element to show
|
||||
*/
|
||||
showInnerContainer(containerSelector) {
|
||||
|
||||
// Before showing the container, make sure there is no other visible.
|
||||
// If we quickly show a container, while another one is animating
|
||||
// and animation never ends, so we do not really hide the first one and
|
||||
// we end up with to shown panels
|
||||
$("#sideToolbarContainer").children().each(function() {
|
||||
if ($(this).hasClass("show"))
|
||||
SideContainerToggler.hideInnerContainer($(this));
|
||||
});
|
||||
|
||||
containerSelector.removeClass("hide").addClass("show");
|
||||
|
||||
this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
||||
|
||||
@@ -17,7 +17,8 @@ const htmlStr = `
|
||||
<div id="nickname">
|
||||
<span data-i18n="chat.nickname.title"></span>
|
||||
<form>
|
||||
<input type='text' id="nickinput" autofocus
|
||||
<input type='text'
|
||||
class="input-control" id="nickinput" autofocus
|
||||
data-i18n="[placeholder]chat.nickname.popover">
|
||||
</form>
|
||||
</div>
|
||||
@@ -156,6 +157,17 @@ function resizeChatConversation() {
|
||||
chat.height(window.innerHeight - 15 - msgareaHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus input after 400 ms
|
||||
* Found input by id
|
||||
*
|
||||
* @param id {string} input id
|
||||
*/
|
||||
function deferredFocus(id){
|
||||
setTimeout(function (){
|
||||
$(`#${id}`).focus();
|
||||
}, 400);
|
||||
}
|
||||
/**
|
||||
* Chat related user interface.
|
||||
*/
|
||||
@@ -179,6 +191,7 @@ var Chat = {
|
||||
let val = this.value;
|
||||
this.value = '';
|
||||
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
|
||||
deferredFocus('usermsg');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -222,9 +235,9 @@ var Chat = {
|
||||
// if we are in conversation mode focus on the text input
|
||||
// if we are not, focus on the display name input
|
||||
if (APP.settings.getDisplayName())
|
||||
$('#usermsg').focus();
|
||||
deferredFocus('usermsg');
|
||||
else
|
||||
$('#nickinput').focus();
|
||||
deferredFocus('nickinput');
|
||||
});
|
||||
|
||||
addSmileys();
|
||||
@@ -296,12 +309,11 @@ var Chat = {
|
||||
if (subject) {
|
||||
subject = subject.trim();
|
||||
}
|
||||
$('#subject').html(linkify(UIUtil.escapeHtml(subject)));
|
||||
if (subject) {
|
||||
$("#subject").css({display: "block"});
|
||||
} else {
|
||||
$("#subject").css({display: "none"});
|
||||
}
|
||||
|
||||
let subjectId = 'subject';
|
||||
let html = linkify(UIUtil.escapeHtml(subject));
|
||||
$(`#${subjectId}`).html(html);
|
||||
UIUtil.setVisible(subjectId, subject && subject.length > 0);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -314,13 +326,6 @@ var Chat = {
|
||||
setChatConversationMode (isConversationMode) {
|
||||
$('#' + CHAT_CONTAINER_ID)
|
||||
.toggleClass('is-conversation-mode', isConversationMode);
|
||||
|
||||
// this is needed when we transition from no conversation mode to
|
||||
// conversation mode. When user enters his nickname and hits enter,
|
||||
// to focus on the write area.
|
||||
if (isConversationMode) {
|
||||
$('#usermsg').focus();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global $, APP, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import Avatar from '../../avatar/Avatar';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import UIUtil from '../../util/UIUtil';
|
||||
@@ -27,7 +29,7 @@ function updateNumberOfParticipants(delta) {
|
||||
numberOfContacts += delta;
|
||||
|
||||
if (numberOfContacts <= 0) {
|
||||
console.error("Invalid number of participants: " + numberOfContacts);
|
||||
logger.error("Invalid number of participants: " + numberOfContacts);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,7 +138,7 @@ var ContactListView = {
|
||||
* Adds layout for lock description
|
||||
*/
|
||||
getLockDescriptionLayout(key) {
|
||||
let classes = "input-control__hint input-control_full-width";
|
||||
let classes = "form-control__hint form-control_full-width";
|
||||
let padlockSuffix = '';
|
||||
if (key === this.lockKey) {
|
||||
padlockSuffix = '-locked';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* global $ */
|
||||
/* global $, APP, JitsiMeetJS */
|
||||
import UIUtil from "../../util/UIUtil";
|
||||
import UIEvents from "../../../../service/UI/UIEvents";
|
||||
import Settings from '../../../settings/Settings';
|
||||
@@ -10,23 +10,23 @@ const htmlStr = `
|
||||
<div class="sideToolbarBlock first">
|
||||
<label class="first" data-i18n="profile.setDisplayNameLabel">
|
||||
</label>
|
||||
<input type="text" id="setDisplayName"
|
||||
<input class="input-control" type="text" id="setDisplayName"
|
||||
data-i18n="[placeholder]settings.name">
|
||||
</div>
|
||||
<div class="sideToolbarBlock">
|
||||
<label data-i18n="profile.setEmailLabel"></label>
|
||||
<input id="setEmail" type="text"
|
||||
<input id="setEmail" type="text" class="input-control"
|
||||
data-i18n="[placeholder]profile.setEmailInput">
|
||||
</div>
|
||||
<div id="authenticationContainer"
|
||||
<div id="profile_auth_container"
|
||||
class="sideToolbarBlock auth_container">
|
||||
<p data-i18n="toolbar.authenticate"></p>
|
||||
<ul>
|
||||
<li id="toolbar_auth_identity"></li>
|
||||
<li id="toolbar_button_login">
|
||||
<li id="profile_auth_identity"></li>
|
||||
<li id="profile_button_login">
|
||||
<a class="authButton" data-i18n="toolbar.login"></a>
|
||||
</li>
|
||||
<li id="toolbar_button_logout">
|
||||
<li id="profile_button_logout">
|
||||
<a class="authButton" data-i18n="toolbar.logout"></a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -68,6 +68,34 @@ export default {
|
||||
updateEmail();
|
||||
}
|
||||
}).focusout(updateEmail);
|
||||
|
||||
// LOGIN
|
||||
function loginClicked () {
|
||||
JitsiMeetJS.analytics.sendEvent('authenticate.login.clicked');
|
||||
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||
}
|
||||
|
||||
$('#profile_button_login').click(loginClicked);
|
||||
|
||||
// LOGOUT
|
||||
function logoutClicked () {
|
||||
let titleKey = "dialog.logoutTitle";
|
||||
let msgKey = "dialog.logoutQuestion";
|
||||
JitsiMeetJS.analytics.sendEvent('authenticate.logout.clicked');
|
||||
// Ask for confirmation
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey: titleKey,
|
||||
msgKey: msgKey,
|
||||
leftButtonKey: "dialog.Yes",
|
||||
submitFunction: function (evt, yes) {
|
||||
if (yes) {
|
||||
emitter.emit(UIEvents.LOGOUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('#profile_button_logout').click(logoutClicked);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -92,5 +120,46 @@ export default {
|
||||
*/
|
||||
changeAvatar (avatarUrl) {
|
||||
$('#avatar').attr('src', avatarUrl);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows or hides authentication related buttons
|
||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
showAuthenticationButtons (show) {
|
||||
let id = 'profile_auth_container';
|
||||
UIUtil.setVisible(id, show);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides login button.
|
||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
showLoginButton (show) {
|
||||
let id = 'profile_button_login';
|
||||
|
||||
UIUtil.setVisible(id, show);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides logout button.
|
||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
showLogoutButton (show) {
|
||||
let id = 'profile_button_logout';
|
||||
|
||||
UIUtil.setVisible(id, show);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays user's authenticated identity name (login).
|
||||
* @param {string} authIdentity identity name to be displayed.
|
||||
*/
|
||||
setAuthenticatedIdentity (authIdentity) {
|
||||
let id = 'profile_auth_identity';
|
||||
|
||||
UIUtil.setVisible(id, !!authIdentity);
|
||||
|
||||
$(`#${id}`).text(authIdentity ? authIdentity : '');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -166,7 +166,7 @@ export default {
|
||||
APP.translation.addLanguageChangedListener(
|
||||
lng => selectInput[0].dataset.i18n = `languages:${lng}`);
|
||||
|
||||
UIUtil.showElement(wrapperId);
|
||||
UIUtil.setVisible(wrapperId, true);
|
||||
}
|
||||
// DEVICES LIST
|
||||
if (UIUtil.isSettingEnabled('devices')) {
|
||||
@@ -181,9 +181,9 @@ export default {
|
||||
});
|
||||
// Only show the subtitle if this isn't the only setting section.
|
||||
if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
|
||||
UIUtil.showElement("deviceOptionsTitle");
|
||||
UIUtil.setVisible("deviceOptionsTitle", true);
|
||||
|
||||
UIUtil.showElement(wrapperId);
|
||||
UIUtil.setVisible(wrapperId, true);
|
||||
}
|
||||
// MODERATOR
|
||||
if (UIUtil.isSettingEnabled('moderator')) {
|
||||
@@ -208,7 +208,7 @@ export default {
|
||||
emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
|
||||
});
|
||||
|
||||
UIUtil.showElement(wrapperId);
|
||||
UIUtil.setVisible(wrapperId, true);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -245,15 +245,15 @@ export default {
|
||||
// Only show the subtitle if this isn't the only setting section.
|
||||
if (!$("#moderatorOptionsTitle").is(":visible")
|
||||
&& interfaceConfig.SETTINGS_SECTIONS.length > 1)
|
||||
UIUtil.showElement("moderatorOptionsTitle");
|
||||
UIUtil.setVisible("moderatorOptionsTitle", true);
|
||||
|
||||
UIUtil.showElement("startMutedOptions");
|
||||
UIUtil.setVisible("startMutedOptions", true);
|
||||
} else {
|
||||
// Only show the subtitle if this isn't the only setting section.
|
||||
if ($("#moderatorOptionsTitle").is(":visible"))
|
||||
UIUtil.hideElement("moderatorOptionsTitle");
|
||||
UIUtil.setVisible("moderatorOptionsTitle", false);
|
||||
|
||||
UIUtil.hideElement("startMutedOptions");
|
||||
UIUtil.setVisible("startMutedOptions", false);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -268,11 +268,9 @@ export default {
|
||||
* @param {boolean} show {true} to show those options, {false} to hide them
|
||||
*/
|
||||
showFollowMeOptions (show) {
|
||||
if (show && UIUtil.isSettingEnabled('moderator')) {
|
||||
UIUtil.showElement("followMeOptions");
|
||||
} else {
|
||||
UIUtil.hideElement("followMeOptions");
|
||||
}
|
||||
UIUtil.setVisible(
|
||||
"followMeOptions",
|
||||
show && UIUtil.isSettingEnabled('moderator'));
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
63
modules/UI/suspended_overlay/SuspendedOverlay.js
Normal file
63
modules/UI/suspended_overlay/SuspendedOverlay.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/* global $, APP */
|
||||
|
||||
import Overlay from '../overlay/Overlay';
|
||||
|
||||
/**
|
||||
* An overlay dialog which is shown when a suspended event is detected.
|
||||
*/
|
||||
class SuspendedOverlayImpl extends Overlay{
|
||||
/**
|
||||
* Creates new <tt>SuspendedOverlayImpl</tt>
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
$(document).on('click', '#rejoin', () => {
|
||||
APP.ConferenceUrl.reload();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Constructs overlay body with the message and a button to rejoin.
|
||||
* @override
|
||||
*/
|
||||
_buildOverlayContent() {
|
||||
return (
|
||||
`<div class="inlay">
|
||||
<span class="inlay__icon icon-microphone"></span>
|
||||
<span class="inlay__icon icon-camera"></span>
|
||||
<h3 class="inlay__title" data-i18n="suspendedoverlay.title"></h3>
|
||||
<button id="rejoin"
|
||||
data-i18n="suspendedoverlay.rejoinKeyTitle"
|
||||
class="inlay__button button-control button-control_primary">
|
||||
</button>
|
||||
</div>`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the page suspended overlay instance.
|
||||
*
|
||||
* {@type SuspendedOverlayImpl}
|
||||
*/
|
||||
let overlay;
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Checks whether the page suspended overlay has been displayed.
|
||||
* @return {boolean} <tt>true</tt> if the page suspended overlay is
|
||||
* currently visible or <tt>false</tt> otherwise.
|
||||
*/
|
||||
isVisible() {
|
||||
return overlay && overlay.isVisible();
|
||||
},
|
||||
/**
|
||||
* Shows the page suspended overlay.
|
||||
*/
|
||||
show() {
|
||||
|
||||
if (!overlay) {
|
||||
overlay = new SuspendedOverlayImpl();
|
||||
}
|
||||
overlay.show();
|
||||
}
|
||||
};
|
||||
@@ -97,30 +97,6 @@ const buttonHandlers = {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.hangup');
|
||||
emitter.emit(UIEvents.HANGUP);
|
||||
},
|
||||
"toolbar_button_login": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.login.clicked');
|
||||
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||
},
|
||||
"toolbar_button_logout": function () {
|
||||
let titleKey = "dialog.logoutTitle";
|
||||
let msgKey = "dialog.logoutQuestion";
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.authenticate.logout.clicked');
|
||||
// Ask for confirmation
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
titleKey,
|
||||
msgKey,
|
||||
leftButtonKey: "dialog.Yes",
|
||||
submitFunction: function (evt, yes) {
|
||||
if (yes) {
|
||||
emitter.emit(UIEvents.LOGOUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
"toolbar_film_strip": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.filmstrip.toggled');
|
||||
emitter.emit(UIEvents.TOGGLE_FILM_STRIP);
|
||||
},
|
||||
"toolbar_button_raisehand": function () {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.raiseHand.clicked');
|
||||
APP.conference.maybeToggleRaisedHand();
|
||||
@@ -261,18 +237,6 @@ const defaultToolbarButtons = {
|
||||
content: "Hang Up",
|
||||
i18n: "[content]toolbar.hangup"
|
||||
},
|
||||
'filmstrip': {
|
||||
id: 'toolbar_film_strip',
|
||||
tooltipKey: 'toolbar.filmstrip',
|
||||
className: "button icon-toggle-filmstrip",
|
||||
shortcut: "F",
|
||||
shortcutAttr: "filmstripPopover",
|
||||
shortcutFunc: function() {
|
||||
JitsiMeetJS.analytics.sendEvent("shortcut.film.toggled");
|
||||
APP.UI.toggleFilmStrip();
|
||||
},
|
||||
shortcutDescription: "keyboardShortcuts.toggleFilmstrip"
|
||||
},
|
||||
'raisehand': {
|
||||
id: "toolbar_button_raisehand",
|
||||
tooltipKey: 'toolbar.raiseHand',
|
||||
@@ -291,7 +255,9 @@ const defaultToolbarButtons = {
|
||||
'recording': {
|
||||
id: 'toolbar_button_record',
|
||||
tooltipKey: 'liveStreaming.buttonTooltip',
|
||||
className: 'button'
|
||||
className: 'button',
|
||||
hidden: true // will be displayed once
|
||||
// the recording functionality is detected
|
||||
},
|
||||
'sharedvideo': {
|
||||
id: 'toolbar_button_sharedvideo',
|
||||
@@ -306,7 +272,9 @@ const defaultToolbarButtons = {
|
||||
'sip': {
|
||||
id: 'toolbar_button_sip',
|
||||
tooltipKey: 'toolbar.sip',
|
||||
className: 'button icon-telephone'
|
||||
className: 'button icon-telephone',
|
||||
hidden: true // will be displayed once
|
||||
// the SIP calls functionality is detected
|
||||
},
|
||||
'dialpad': {
|
||||
id: 'toolbar_button_dialpad',
|
||||
@@ -327,7 +295,8 @@ function showSipNumberInput () {
|
||||
: '';
|
||||
let titleKey = "dialog.sipMsg";
|
||||
let msgString = (`
|
||||
<input name="sipNumber" type="text"
|
||||
<input class="input-control"
|
||||
name="sipNumber" type="text"
|
||||
value="${defaultNumber}" autofocus>`);
|
||||
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
@@ -412,15 +381,6 @@ Toolbar = {
|
||||
isEnabled() {
|
||||
return this.enabled;
|
||||
},
|
||||
/**
|
||||
* Shows or hides authentication button
|
||||
* @param show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
showAuthenticateButton (show) {
|
||||
let display = show ? 'block' : 'none';
|
||||
|
||||
$('#authenticationContainer').css({display});
|
||||
},
|
||||
|
||||
showEtherpadButton () {
|
||||
if (!$('#toolbar_button_etherpad').is(":visible")) {
|
||||
@@ -430,14 +390,15 @@ Toolbar = {
|
||||
|
||||
// Shows or hides the 'shared video' button.
|
||||
showSharedVideoButton () {
|
||||
let $element = $('#toolbar_button_sharedvideo');
|
||||
if (UIUtil.isButtonEnabled('sharedvideo')
|
||||
&& config.disableThirdPartyRequests !== true) {
|
||||
$element.css({display: "inline-block"});
|
||||
UIUtil.setTooltip($element.get(0), 'toolbar.sharedvideo', 'right');
|
||||
} else {
|
||||
$('#toolbar_button_sharedvideo').css({display: "none"});
|
||||
let id = 'toolbar_button_sharedvideo';
|
||||
let shouldShow = UIUtil.isButtonEnabled('sharedvideo')
|
||||
&& !config.disableThirdPartyRequests;
|
||||
|
||||
if (shouldShow) {
|
||||
let el = document.getElementById(id);
|
||||
UIUtil.setTooltip(el, 'toolbar.sharedvideo', 'right');
|
||||
}
|
||||
UIUtil.setVisible(id, shouldShow);
|
||||
},
|
||||
|
||||
// checks whether desktop sharing is enabled and whether
|
||||
@@ -451,61 +412,19 @@ Toolbar = {
|
||||
|
||||
// Shows or hides SIP calls button
|
||||
showSipCallButton (show) {
|
||||
if (APP.conference.sipGatewayEnabled()
|
||||
&& UIUtil.isButtonEnabled('sip') && show) {
|
||||
$('#toolbar_button_sip').css({display: "inline-block"});
|
||||
} else {
|
||||
$('#toolbar_button_sip').css({display: "none"});
|
||||
}
|
||||
let shouldShow = APP.conference.sipGatewayEnabled()
|
||||
&& UIUtil.isButtonEnabled('sip') && show;
|
||||
let id = 'toolbar_button_sip';
|
||||
|
||||
UIUtil.setVisible(id, shouldShow);
|
||||
},
|
||||
|
||||
// Shows or hides the dialpad button
|
||||
showDialPadButton (show) {
|
||||
if (UIUtil.isButtonEnabled('dialpad') && show) {
|
||||
$('#toolbar_button_dialpad').css({display: "inline-block"});
|
||||
} else {
|
||||
$('#toolbar_button_dialpad').css({display: "none"});
|
||||
}
|
||||
},
|
||||
let shouldShow = UIUtil.isButtonEnabled('dialpad') && show;
|
||||
let id = 'toolbar_button_dialpad';
|
||||
|
||||
/**
|
||||
* Displays user authenticated identity name(login).
|
||||
* @param authIdentity identity name to be displayed.
|
||||
*/
|
||||
setAuthenticatedIdentity (authIdentity) {
|
||||
let selector = $('#toolbar_auth_identity');
|
||||
|
||||
if (authIdentity) {
|
||||
selector.css({display: "list-item"});
|
||||
selector.text(authIdentity);
|
||||
} else {
|
||||
selector.css({display: "none"});
|
||||
selector.text('');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides login button.
|
||||
* @param show <tt>true</tt> to show
|
||||
*/
|
||||
showLoginButton (show) {
|
||||
if (show) {
|
||||
$('#toolbar_button_login').css({display: "list-item"});
|
||||
} else {
|
||||
$('#toolbar_button_login').css({display: "none"});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides logout button.
|
||||
* @param show <tt>true</tt> to show
|
||||
*/
|
||||
showLogoutButton (show) {
|
||||
if (show) {
|
||||
$('#toolbar_button_logout').css({display: "list-item"});
|
||||
} else {
|
||||
$('#toolbar_button_logout').css({display: "none"});
|
||||
}
|
||||
UIUtil.setVisible(id, shouldShow);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,7 +69,7 @@ var JitsiPopover = (function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides the popover
|
||||
* Hides the popover if not hovered or popover is not shown.
|
||||
*/
|
||||
JitsiPopover.prototype.hide = function () {
|
||||
if(!this.elementIsHovered && !this.popoverIsHovered &&
|
||||
@@ -79,7 +79,7 @@ var JitsiPopover = (function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides the popover.
|
||||
* Hides the popover and clears the document elements added by popover.
|
||||
*/
|
||||
JitsiPopover.prototype.forceHide = function () {
|
||||
$(".jitsipopover").remove();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global $, APP, toastr */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import UIUtil from './UIUtil';
|
||||
import jitsiLocalStorage from '../../util/JitsiLocalStorage';
|
||||
@@ -79,7 +80,7 @@ function dontShowTheDialog(options) {
|
||||
function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
|
||||
if(isDontShowAgainEnabled(options)) {
|
||||
return (...args) => {
|
||||
console.debug(args, options.buttonValues);
|
||||
logger.debug(args, options.buttonValues);
|
||||
//args[1] is the value associated with the pressed button
|
||||
if(!options.buttonValues || options.buttonValues.length === 0
|
||||
|| options.buttonValues.indexOf(args[1]) !== -1 ) {
|
||||
@@ -127,7 +128,8 @@ var messageHandler = {
|
||||
return null;
|
||||
|
||||
let dialog = $.prompt(
|
||||
APP.translation.generateTranslationHTML(messageKey, i18nOptions), {
|
||||
APP.translation.generateTranslationHTML(messageKey, i18nOptions),
|
||||
{
|
||||
title: this._getFormattedTitleString(titleKey),
|
||||
persistent: false,
|
||||
promptspeed: 0,
|
||||
@@ -289,7 +291,15 @@ var messageHandler = {
|
||||
buttons: buttons,
|
||||
defaultButton: 1,
|
||||
promptspeed: 0,
|
||||
loaded: loadedFunction,
|
||||
loaded: function() {
|
||||
if (loadedFunction) {
|
||||
loadedFunction.apply(this, arguments);
|
||||
}
|
||||
// Hide the close button
|
||||
if (persistent) {
|
||||
$(".jqiclose", this).hide();
|
||||
}
|
||||
},
|
||||
submit: dontShowAgainSubmitFunctionWrapper(
|
||||
dontShowAgain, submitFunction),
|
||||
close: closeFunction,
|
||||
@@ -408,7 +418,7 @@ var messageHandler = {
|
||||
*/
|
||||
openReportDialog: function(titleKey, msgKey, error) {
|
||||
this.openMessageDialog(titleKey, msgKey);
|
||||
console.log(error);
|
||||
logger.log(error);
|
||||
//FIXME send the error to the server
|
||||
},
|
||||
|
||||
@@ -438,7 +448,7 @@ var messageHandler = {
|
||||
* @param messageKey the key from the language file for the text of the
|
||||
* message.
|
||||
* @param messageArguments object with the arguments for the message.
|
||||
* @param options object with language options.
|
||||
* @param options passed to toastr (e.g. timeOut)
|
||||
*/
|
||||
notify: function(displayName, displayNameKey, cls, messageKey,
|
||||
messageArguments, options) {
|
||||
|
||||
@@ -18,6 +18,34 @@ const TOOLTIP_POSITIONS = {
|
||||
'top-right': 'sw'
|
||||
};
|
||||
|
||||
/**
|
||||
* Associates the default display type with corresponding CSS class
|
||||
*/
|
||||
const SHOW_CLASSES = {
|
||||
'block': 'show',
|
||||
'inline': 'show-inline',
|
||||
'list-item': 'show-list-item'
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains sizes of thumbnails
|
||||
* @type {{SMALL: number, MEDIUM: number}}
|
||||
*/
|
||||
const ThumbnailSizes = {
|
||||
SMALL: 60,
|
||||
MEDIUM: 80
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains font sizes for thumbnail indicators
|
||||
* @type {{SMALL: number, MEDIUM: number}}
|
||||
*/
|
||||
const IndicatorFontSizes = {
|
||||
SMALL: 5,
|
||||
MEDIUM: 6,
|
||||
NORMAL: 8
|
||||
};
|
||||
|
||||
/**
|
||||
* Created by hristo on 12/22/14.
|
||||
*/
|
||||
@@ -27,9 +55,7 @@ const TOOLTIP_POSITIONS = {
|
||||
* Returns the available video width.
|
||||
*/
|
||||
getAvailableVideoWidth: function () {
|
||||
let rightPanelWidth = 0;
|
||||
|
||||
return window.innerWidth - rightPanelWidth;
|
||||
return window.innerWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -214,38 +240,66 @@ const TOOLTIP_POSITIONS = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the element given by id.
|
||||
* Shows / hides the element given by id.
|
||||
*
|
||||
* @param {String} the identifier of the element to show
|
||||
* @param {string|HTMLElement} idOrElement the identifier or the element
|
||||
* to show/hide
|
||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||
*/
|
||||
showElement(id) {
|
||||
if ($("#"+id).hasClass("hide"))
|
||||
$("#"+id).removeClass("hide");
|
||||
setVisible(id, visible) {
|
||||
let element;
|
||||
if (id instanceof HTMLElement) {
|
||||
element = id;
|
||||
} else {
|
||||
element = document.getElementById(id);
|
||||
}
|
||||
|
||||
$("#"+id).addClass("show");
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!visible)
|
||||
element.classList.add('hide');
|
||||
else if (element.classList.contains('hide')) {
|
||||
element.classList.remove('hide');
|
||||
}
|
||||
|
||||
let type = this._getElementDefaultDisplay(element.tagName);
|
||||
let className = SHOW_CLASSES[type];
|
||||
|
||||
if (visible) {
|
||||
element.classList.add(className);
|
||||
}
|
||||
else if (element.classList.contains(className))
|
||||
element.classList.remove(className);
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the element given by id.
|
||||
*
|
||||
* @param {String} the identifier of the element to hide
|
||||
* Returns default display style for the tag
|
||||
* @param tag
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
hideElement(id) {
|
||||
if ($("#"+id).hasClass("show"))
|
||||
$("#"+id).removeClass("show");
|
||||
_getElementDefaultDisplay(tag) {
|
||||
let tempElement = document.createElement(tag);
|
||||
|
||||
$("#"+id).addClass("hide");
|
||||
document.body.appendChild(tempElement);
|
||||
let style = window.getComputedStyle(tempElement).display;
|
||||
document.body.removeChild(tempElement);
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows / hides the element with the given jQuery selector.
|
||||
*
|
||||
* @param {jQuery} selector the jQuery selector of the element to show/hide
|
||||
* @param {jQuery} jquerySelector the jQuery selector of the element to
|
||||
* show / shide
|
||||
* @param {boolean} isVisible
|
||||
*/
|
||||
setVisibility(selector, isVisible) {
|
||||
if (selector && selector.length > 0) {
|
||||
selector.css("visibility", isVisible ? "visible" : "hidden");
|
||||
setVisibleBySelector(jquerySelector, isVisible) {
|
||||
if (jquerySelector && jquerySelector.length > 0) {
|
||||
jquerySelector.css("visibility", isVisible ? "visible" : "hidden");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -411,6 +465,7 @@ const TOOLTIP_POSITIONS = {
|
||||
|
||||
if (indicators.length <= 0) {
|
||||
indicatorSpan = document.createElement('span');
|
||||
|
||||
indicatorSpan.className = 'indicator';
|
||||
indicatorSpan.id = indicatorId;
|
||||
|
||||
@@ -423,6 +478,8 @@ const TOOLTIP_POSITIONS = {
|
||||
APP.translation.translateElement($(indicatorSpan));
|
||||
}
|
||||
|
||||
this._resizeIndicator(indicatorSpan);
|
||||
|
||||
document.getElementById(videoSpanId)
|
||||
.querySelector('.videocontainer__toptoolbar')
|
||||
.appendChild(indicatorSpan);
|
||||
@@ -431,6 +488,37 @@ const TOOLTIP_POSITIONS = {
|
||||
}
|
||||
|
||||
return indicatorSpan;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizing indicator element passing via argument
|
||||
* according to the current thumbnail size
|
||||
* @param {HTMLElement} indicator - indicator element
|
||||
* @private
|
||||
*/
|
||||
_resizeIndicator(indicator) {
|
||||
let height = $('#localVideoContainer').height();
|
||||
let fontSize = this.getIndicatorFontSize(height);
|
||||
$(indicator).css('font-size', fontSize);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns font size for indicators according to current
|
||||
* height of thumbnail
|
||||
* @param {Number} - height - current height of thumbnail
|
||||
* @returns {Number} - font size for current height
|
||||
*/
|
||||
getIndicatorFontSize(height) {
|
||||
const { SMALL, MEDIUM } = ThumbnailSizes;
|
||||
let fontSize = IndicatorFontSizes.NORMAL;
|
||||
|
||||
if (height <= SMALL) {
|
||||
fontSize = IndicatorFontSizes.SMALL;
|
||||
} else if (height > SMALL && height <= MEDIUM) {
|
||||
fontSize = IndicatorFontSizes.MEDIUM;
|
||||
}
|
||||
|
||||
return fontSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* global $, interfaceConfig */
|
||||
/* global $, APP, JitsiMeetJS, interfaceConfig */
|
||||
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
@@ -12,6 +12,7 @@ const FilmStrip = {
|
||||
init (eventEmitter) {
|
||||
this.iconMenuDownClassName = 'icon-menu-down';
|
||||
this.iconMenuUpClassName = 'icon-menu-up';
|
||||
this.filmStripContainerClassName = 'filmstrip';
|
||||
this.filmStrip = $('#remoteVideos');
|
||||
this.eventEmitter = eventEmitter;
|
||||
this._initFilmStripToolbar();
|
||||
@@ -23,7 +24,8 @@ const FilmStrip = {
|
||||
*/
|
||||
_initFilmStripToolbar() {
|
||||
let toolbar = this._generateFilmStripToolbar();
|
||||
let container = document.querySelector('.filmstrip');
|
||||
let className = this.filmStripContainerClassName;
|
||||
let container = document.querySelector(`.${className}`);
|
||||
|
||||
UIUtil.prependChild(container, toolbar);
|
||||
|
||||
@@ -55,9 +57,36 @@ const FilmStrip = {
|
||||
* Attach 'click' listener to "hide filmstrip" button
|
||||
*/
|
||||
registerListeners() {
|
||||
let toggleFilmstripMethod = this.toggleFilmStrip.bind(this);
|
||||
let selector = '#hideVideoToolbar';
|
||||
$('#videospace').on('click', selector, toggleFilmstripMethod);
|
||||
// Important:
|
||||
// Firing the event instead of executing toggleFilmstrip method because
|
||||
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
||||
// to correctly resize the video area.
|
||||
$('#hideVideoToolbar').on('click',
|
||||
() => this.eventEmitter.emit(UIEvents.TOGGLE_FILM_STRIP));
|
||||
|
||||
this._registerToggleFilmstripShortcut();
|
||||
},
|
||||
|
||||
/**
|
||||
* Registering toggle filmstrip shortcut
|
||||
* @private
|
||||
*/
|
||||
_registerToggleFilmstripShortcut() {
|
||||
let shortcut = 'F';
|
||||
let shortcutAttr = 'filmstripPopover';
|
||||
let description = 'keyboardShortcuts.toggleFilmstrip';
|
||||
// Important:
|
||||
// Firing the event instead of executing toggleFilmstrip method because
|
||||
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
||||
// to correctly resize the video area.
|
||||
let handler = () => this.eventEmitter.emit(UIEvents.TOGGLE_FILM_STRIP);
|
||||
|
||||
APP.keyboardshortcut.registerShortcut(
|
||||
shortcut,
|
||||
shortcutAttr,
|
||||
handler,
|
||||
description
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -85,6 +114,11 @@ const FilmStrip = {
|
||||
* of the film strip. If not specified, the visibility will be flipped
|
||||
* (i.e. toggled); otherwise, the visibility will be set to the specified
|
||||
* value.
|
||||
*
|
||||
* Note:
|
||||
* This method shouldn't be executed directly to hide the filmstrip.
|
||||
* It's important to hide the filmstrip with UI.toggleFilmstrip in order
|
||||
* to correctly resize the video area.
|
||||
*/
|
||||
toggleFilmStrip(visible) {
|
||||
let isVisibleDefined = typeof visible === 'boolean';
|
||||
@@ -93,7 +127,7 @@ const FilmStrip = {
|
||||
} else if (this.isFilmStripVisible() === visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.filmstrip.toggled');
|
||||
this.filmStrip.toggleClass("hidden");
|
||||
|
||||
if (!visible) {
|
||||
@@ -132,7 +166,7 @@ const FilmStrip = {
|
||||
*/
|
||||
getFilmStripHeight() {
|
||||
if (this.isFilmStripVisible()) {
|
||||
return this.filmStrip.outerHeight();
|
||||
return $(`.${this.filmStripContainerClassName}`).outerHeight();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -180,6 +214,7 @@ const FilmStrip = {
|
||||
*/
|
||||
let videoAreaAvailableWidth
|
||||
= UIUtil.getAvailableVideoWidth()
|
||||
- this._getFilmstripExtraPanelsWidth()
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('right'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingLeft'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingRight'), 10)
|
||||
@@ -242,12 +277,35 @@ const FilmStrip = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate the thumbnail size in order to fit all the thumnails in passed
|
||||
* Traverse all elements inside the filmstrip
|
||||
* and calculates the sum of all of them except
|
||||
* remote videos element. Used for calculation of
|
||||
* available width for video thumbnails.
|
||||
*
|
||||
* @returns {number} calculated width
|
||||
* @private
|
||||
*/
|
||||
_getFilmstripExtraPanelsWidth() {
|
||||
let className = this.filmStripContainerClassName;
|
||||
let width = 0;
|
||||
$(`.${className}`)
|
||||
.children()
|
||||
.each(function () {
|
||||
if (this.id !== 'remoteVideos') {
|
||||
width += $(this).outerWidth();
|
||||
}
|
||||
});
|
||||
return width;
|
||||
},
|
||||
|
||||
/**
|
||||
Calculate the thumbnail size in order to fit all the thumnails in passed
|
||||
* dimensions.
|
||||
* NOTE: Here we assume that the remote and local thumbnails are with the
|
||||
* same height.
|
||||
* @param {int} availableWidth the maximum width for all thumbnails
|
||||
* @param {int} availableHeight the maximum height for all thumbnails
|
||||
* @returns {{localVideo, remoteVideo}}
|
||||
*/
|
||||
calculateThumbnailSizeFromAvailable(availableWidth, availableHeight) {
|
||||
/**
|
||||
@@ -294,10 +352,12 @@ const FilmStrip = {
|
||||
(remoteLocalWidthRatio * numberRemoteThumbs + 1), availableHeight *
|
||||
interfaceConfig.LOCAL_THUMBNAIL_RATIO);
|
||||
const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
|
||||
return { localVideo:{
|
||||
return {
|
||||
localVideo:{
|
||||
thumbWidth: lW,
|
||||
thumbHeight: h
|
||||
}, remoteVideo: {
|
||||
},
|
||||
remoteVideo: {
|
||||
thumbWidth: lW * remoteLocalWidthRatio,
|
||||
thumbHeight: h
|
||||
}
|
||||
@@ -317,39 +377,63 @@ const FilmStrip = {
|
||||
|
||||
return new Promise(resolve => {
|
||||
let thumbs = this.getThumbs(!forceUpdate);
|
||||
if(thumbs.localThumb)
|
||||
thumbs.localThumb.animate({
|
||||
height: local.thumbHeight,
|
||||
width: local.thumbWidth
|
||||
}, {
|
||||
queue: false,
|
||||
duration: animate ? 500 : 0,
|
||||
complete: resolve
|
||||
});
|
||||
if(thumbs.remoteThumbs)
|
||||
thumbs.remoteThumbs.animate({
|
||||
height: remote.thumbHeight,
|
||||
width: remote.thumbWidth
|
||||
}, {
|
||||
queue: false,
|
||||
duration: animate ? 500 : 0,
|
||||
complete: resolve
|
||||
});
|
||||
let promises = [];
|
||||
|
||||
this.filmStrip.animate({
|
||||
// adds 2 px because of small video 1px border
|
||||
height: remote.thumbHeight + 2
|
||||
}, {
|
||||
queue: false,
|
||||
duration: animate ? 500 : 0
|
||||
});
|
||||
if(thumbs.localThumb) {
|
||||
promises.push(new Promise((resolve) => {
|
||||
thumbs.localThumb.animate({
|
||||
height: local.thumbHeight,
|
||||
width: local.thumbWidth
|
||||
}, this._getAnimateOptions(animate, resolve));
|
||||
}));
|
||||
}
|
||||
if(thumbs.remoteThumbs) {
|
||||
promises.push(new Promise((resolve) => {
|
||||
thumbs.remoteThumbs.animate({
|
||||
height: remote.thumbHeight,
|
||||
width: remote.thumbWidth
|
||||
}, this._getAnimateOptions(animate, resolve));
|
||||
}));
|
||||
}
|
||||
promises.push(new Promise((resolve) => {
|
||||
this.filmStrip.animate({
|
||||
// adds 2 px because of small video 1px border
|
||||
height: remote.thumbHeight + 2
|
||||
}, this._getAnimateOptions(animate, resolve));
|
||||
}));
|
||||
|
||||
promises.push(new Promise(() => {
|
||||
let { localThumb } = this.getThumbs();
|
||||
let height = localThumb.height();
|
||||
let fontSize = UIUtil.getIndicatorFontSize(height);
|
||||
this.filmStrip.find('.indicator').animate({
|
||||
fontSize
|
||||
}, this._getAnimateOptions(animate, resolve));
|
||||
}));
|
||||
|
||||
if (!animate) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
Promise.all(promises).then(resolve);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper method. Returns options for jQuery animation
|
||||
* @param animate {Boolean} - animation flag
|
||||
* @param cb {Function} - complete callback
|
||||
* @returns {Object} - animation options object
|
||||
* @private
|
||||
*/
|
||||
_getAnimateOptions(animate, cb = $.noop) {
|
||||
return {
|
||||
queue: false,
|
||||
duration: animate ? 500 : 0,
|
||||
complete: cb
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns thumbnails of the filmstrip
|
||||
* @param only_visible
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global $, APP, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import Avatar from "../avatar/Avatar";
|
||||
import {createDeferred} from '../../util/helpers';
|
||||
@@ -24,7 +25,7 @@ export default class LargeVideoManager {
|
||||
() => this.resizeContainer(VIDEO_CONTAINER_TYPE), emitter);
|
||||
this.addContainer(VIDEO_CONTAINER_TYPE, this.videoContainer);
|
||||
|
||||
// use the same video container to handle and desktop tracks
|
||||
// use the same video container to handle desktop tracks
|
||||
this.addContainer("desktop", this.videoContainer);
|
||||
|
||||
this.width = 0;
|
||||
@@ -126,7 +127,7 @@ export default class LargeVideoManager {
|
||||
const { id, stream, videoType, resolve } = this.newStreamData;
|
||||
this.newStreamData = null;
|
||||
|
||||
console.info("hover in %s", id);
|
||||
logger.info("hover in %s", id);
|
||||
this.state = videoType;
|
||||
const container = this.getContainer(this.state);
|
||||
container.setStream(stream, videoType);
|
||||
@@ -332,13 +333,14 @@ export default class LargeVideoManager {
|
||||
show = APP.conference.isConnectionInterrupted();
|
||||
}
|
||||
|
||||
let id = 'localConnectionMessage';
|
||||
|
||||
UIUtil.setVisible(id, show);
|
||||
|
||||
if (show) {
|
||||
$('#localConnectionMessage').css({display: "block"});
|
||||
// Avatar message conflicts with 'videoConnectionMessage',
|
||||
// so it must be hidden
|
||||
this.showRemoteConnectionMessage(false);
|
||||
} else {
|
||||
$('#localConnectionMessage').css({display: "none"});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global $, config, interfaceConfig, APP, JitsiMeetJS */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import ConnectionIndicator from "./ConnectionIndicator";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
@@ -40,7 +42,7 @@ LocalVideo.prototype.constructor = LocalVideo;
|
||||
*/
|
||||
LocalVideo.prototype.setDisplayName = function(displayName) {
|
||||
if (!this.container) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
"Unable to set displayName - " + this.videoSpanId +
|
||||
" does not exist");
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global $, APP, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import ConnectionIndicator from './ConnectionIndicator';
|
||||
|
||||
@@ -105,6 +106,14 @@ RemoteVideo.prototype._initPopupMenu = function (popupMenuElement) {
|
||||
// call the original show, passing its actual this
|
||||
origShowFunc.call(this.popover);
|
||||
}.bind(this);
|
||||
|
||||
// override popover hide method so we can cleanup click handlers
|
||||
let origHideFunc = this.popover.forceHide;
|
||||
this.popover.forceHide = function () {
|
||||
$(document).off("click", '#mutelink_' + this.id);
|
||||
$(document).off("click", '#ejectlink_' + this.id);
|
||||
origHideFunc.call(this.popover);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -183,7 +192,7 @@ RemoteVideo.prototype._muteHandler = function () {
|
||||
}
|
||||
}).catch(e => {
|
||||
//currently shouldn't be called
|
||||
console.error(e);
|
||||
logger.error(e);
|
||||
});
|
||||
|
||||
this.popover.forceHide();
|
||||
@@ -335,7 +344,7 @@ RemoteVideo.prototype.removeRemoteStreamElement = function (stream) {
|
||||
this.wasVideoPlayed = false;
|
||||
}
|
||||
|
||||
console.info((isVideo ? "Video" : "Audio") +
|
||||
logger.info((isVideo ? "Video" : "Audio") +
|
||||
" removed " + this.id, select);
|
||||
|
||||
// when removing only the video element and we are on stage
|
||||
@@ -400,7 +409,7 @@ RemoteVideo.prototype.updateConnectionStatusIndicator = function (isActive) {
|
||||
}
|
||||
}
|
||||
|
||||
console.debug(this.id + " thumbnail is connection active ? " + isActive);
|
||||
logger.debug(this.id + " thumbnail is connection active ? " + isActive);
|
||||
|
||||
// Update 'mutedWhileDisconnected' flag
|
||||
this._figureOutMutedWhileDisconnected(!isActive);
|
||||
@@ -419,7 +428,7 @@ RemoteVideo.prototype.updateConnectionStatusIndicator = function (isActive) {
|
||||
* Removes RemoteVideo from the page.
|
||||
*/
|
||||
RemoteVideo.prototype.remove = function () {
|
||||
console.log("Remove thumbnail", this.id);
|
||||
logger.log("Remove thumbnail", this.id);
|
||||
this.removeConnectionIndicator();
|
||||
// Make sure that the large video is updated if are removing its
|
||||
// corresponding small video.
|
||||
@@ -578,7 +587,7 @@ RemoteVideo.prototype.hideConnectionIndicator = function () {
|
||||
*/
|
||||
RemoteVideo.prototype.setDisplayName = function(displayName) {
|
||||
if (!this.container) {
|
||||
console.warn( "Unable to set displayName - " + this.videoSpanId +
|
||||
logger.warn( "Unable to set displayName - " + this.videoSpanId +
|
||||
" does not exist");
|
||||
return;
|
||||
}
|
||||
@@ -628,7 +637,7 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
||||
RemoteVideo.createContainer = function (spanId) {
|
||||
let container = document.createElement('span');
|
||||
container.id = spanId;
|
||||
container.className = 'videocontainer videocontainer_remote';
|
||||
container.className = 'videocontainer';
|
||||
|
||||
let wrapper = document.createElement('div');
|
||||
wrapper.className = 'videocontainer__background';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* global $, JitsiMeetJS, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import Avatar from "../avatar/Avatar";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
@@ -215,16 +217,11 @@ SmallVideo.prototype.hideIndicator = function () {
|
||||
* @param {boolean} isMuted indicates if the muted element should be shown
|
||||
* or hidden
|
||||
*/
|
||||
SmallVideo.prototype.showAudioIndicator = function(isMuted) {
|
||||
SmallVideo.prototype.showAudioIndicator = function (isMuted) {
|
||||
let mutedIndicator = this.getAudioMutedIndicator();
|
||||
|
||||
var audioMutedIndicator = this.getAudioMutedIndicator();
|
||||
UIUtil.setVisible(mutedIndicator, isMuted);
|
||||
|
||||
if (!isMuted) {
|
||||
audioMutedIndicator.hide();
|
||||
}
|
||||
else {
|
||||
audioMutedIndicator.show();
|
||||
}
|
||||
this.isAudioMuted = isMuted;
|
||||
};
|
||||
|
||||
@@ -232,12 +229,13 @@ SmallVideo.prototype.showAudioIndicator = function(isMuted) {
|
||||
* Returns the audio muted indicator jquery object. If it doesn't exists -
|
||||
* creates it.
|
||||
*
|
||||
* @returns {jQuery|HTMLElement} the audio muted indicator
|
||||
* @returns {HTMLElement} the audio muted indicator
|
||||
*/
|
||||
SmallVideo.prototype.getAudioMutedIndicator = function () {
|
||||
var audioMutedSpan = $('#' + this.videoSpanId + ' .audioMuted');
|
||||
let selector = '#' + this.videoSpanId + ' .audioMuted';
|
||||
let audioMutedSpan = document.querySelector(selector);
|
||||
|
||||
if (audioMutedSpan.length) {
|
||||
if (audioMutedSpan) {
|
||||
return audioMutedSpan;
|
||||
}
|
||||
|
||||
@@ -248,16 +246,15 @@ SmallVideo.prototype.getAudioMutedIndicator = function () {
|
||||
"videothumbnail.mute",
|
||||
"top");
|
||||
|
||||
let mutedIndicator = document.createElement('i');
|
||||
mutedIndicator.className = 'icon-mic-disabled';
|
||||
audioMutedSpan.appendChild(mutedIndicator);
|
||||
|
||||
this.container
|
||||
.querySelector('.videocontainer__toolbar')
|
||||
.appendChild(audioMutedSpan);
|
||||
|
||||
|
||||
var mutedIndicator = document.createElement('i');
|
||||
mutedIndicator.className = 'icon-mic-disabled';
|
||||
audioMutedSpan.appendChild(mutedIndicator);
|
||||
|
||||
return $('#' + this.videoSpanId + ' .audioMuted');
|
||||
return audioMutedSpan;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -271,9 +268,9 @@ SmallVideo.prototype.setVideoMutedView = function(isMuted) {
|
||||
this.isVideoMuted = isMuted;
|
||||
this.updateView();
|
||||
|
||||
var videoMutedSpan = this.getVideoMutedIndicator();
|
||||
let element = this.getVideoMutedIndicator();
|
||||
|
||||
videoMutedSpan[isMuted ? 'show' : 'hide']();
|
||||
UIUtil.setVisible(element, isMuted);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -283,9 +280,10 @@ SmallVideo.prototype.setVideoMutedView = function(isMuted) {
|
||||
* @returns {jQuery|HTMLElement} the video muted indicator
|
||||
*/
|
||||
SmallVideo.prototype.getVideoMutedIndicator = function () {
|
||||
var videoMutedSpan = $('#' + this.videoSpanId + ' .videoMuted');
|
||||
var selector = '#' + this.videoSpanId + ' .videoMuted';
|
||||
var videoMutedSpan = document.querySelector(selector);
|
||||
|
||||
if (videoMutedSpan.length) {
|
||||
if (videoMutedSpan) {
|
||||
return videoMutedSpan;
|
||||
}
|
||||
|
||||
@@ -305,7 +303,7 @@ SmallVideo.prototype.getVideoMutedIndicator = function () {
|
||||
|
||||
videoMutedSpan.appendChild(mutedIndicator);
|
||||
|
||||
return $('#' + this.videoSpanId + ' .videoMuted');
|
||||
return videoMutedSpan;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -501,7 +499,7 @@ SmallVideo.prototype.updateView = function () {
|
||||
// Init avatar
|
||||
this.avatarChanged(Avatar.getAvatarUrl(this.id));
|
||||
} else {
|
||||
console.error("Unable to init avatar - no id", this);
|
||||
logger.error("Unable to init avatar - no id", this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -509,24 +507,24 @@ SmallVideo.prototype.updateView = function () {
|
||||
// Determine whether video, avatar or blackness should be displayed
|
||||
let displayMode = this.selectDisplayMode();
|
||||
// Show/hide video.
|
||||
UIUtil.setVisibility( this.selectVideoElement(),
|
||||
(displayMode === DISPLAY_VIDEO
|
||||
UIUtil.setVisibleBySelector(this.selectVideoElement(),
|
||||
(displayMode === DISPLAY_VIDEO
|
||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
|
||||
// Show/hide the avatar.
|
||||
UIUtil.setVisibility( this.$avatar(),
|
||||
(displayMode === DISPLAY_AVATAR
|
||||
UIUtil.setVisibleBySelector(this.$avatar(),
|
||||
(displayMode === DISPLAY_AVATAR
|
||||
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
|
||||
// Show/hide the display name.
|
||||
UIUtil.setVisibility( this.$displayName(),
|
||||
!this.hideDisplayName
|
||||
&& (displayMode === DISPLAY_BLACKNESS_WITH_NAME
|
||||
UIUtil.setVisibleBySelector(this.$displayName(),
|
||||
!this.hideDisplayName
|
||||
&& (displayMode === DISPLAY_BLACKNESS_WITH_NAME
|
||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME
|
||||
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
|
||||
// show hide overlay when there is a video or avatar under
|
||||
// the display name
|
||||
UIUtil.setVisibility( $('#' + this.videoSpanId
|
||||
UIUtil.setVisibleBySelector($('#' + this.videoSpanId
|
||||
+ ' .videocontainer__hoverOverlay'),
|
||||
(displayMode === DISPLAY_AVATAR_WITH_NAME
|
||||
(displayMode === DISPLAY_AVATAR_WITH_NAME
|
||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
|
||||
};
|
||||
|
||||
@@ -559,7 +557,7 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
||||
return;
|
||||
|
||||
if (!this.container) {
|
||||
console.warn( "Unable to set dominant speaker indicator - "
|
||||
logger.warn( "Unable to set dominant speaker indicator - "
|
||||
+ this.videoSpanId + " does not exist");
|
||||
return;
|
||||
}
|
||||
@@ -574,11 +572,7 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
||||
tooltip: 'speaker'
|
||||
});
|
||||
|
||||
if (show) {
|
||||
indicatorSpan.classList.add('show');
|
||||
} else {
|
||||
indicatorSpan.classList.remove('show');
|
||||
}
|
||||
UIUtil.setVisible(indicatorSpan, show);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -587,7 +581,7 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
||||
*/
|
||||
SmallVideo.prototype.showRaisedHandIndicator = function (show) {
|
||||
if (!this.container) {
|
||||
console.warn( "Unable to raised hand indication - "
|
||||
logger.warn( "Unable to raised hand indication - "
|
||||
+ this.videoSpanId + " does not exist");
|
||||
return;
|
||||
}
|
||||
@@ -602,11 +596,7 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
|
||||
tooltip: 'raisedHand'
|
||||
});
|
||||
|
||||
if (show) {
|
||||
indicatorSpan.classList.add('show');
|
||||
} else {
|
||||
indicatorSpan.classList.remove('show');
|
||||
}
|
||||
UIUtil.setVisible(indicatorSpan, show);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,10 @@ function getStreamOwnerId(stream) {
|
||||
* ratio and fits available area with it's larger dimension. This method
|
||||
* ensures that whole video will be visible and can leave empty areas.
|
||||
*
|
||||
* @param videoWidth the width of the video to position
|
||||
* @param videoHeight the height of the video to position
|
||||
* @param videoSpaceWidth the width of the available space
|
||||
* @param videoSpaceHeight the height of the available space
|
||||
* @return an array with 2 elements, the video width and the video height
|
||||
*/
|
||||
function getDesktopVideoSize(videoWidth,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* global config, APP, $, interfaceConfig */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import FilmStrip from "./FilmStrip";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
@@ -261,19 +262,19 @@ var VideoLayout = {
|
||||
if (lastVisible.length) {
|
||||
let id = getPeerContainerResourceId(lastVisible[0]);
|
||||
if (remoteVideos[id]) {
|
||||
console.info("electLastVisibleVideo: " + id);
|
||||
logger.info("electLastVisibleVideo: " + id);
|
||||
return id;
|
||||
}
|
||||
// The RemoteVideo was removed (but the DOM elements may still
|
||||
// exist).
|
||||
}
|
||||
|
||||
console.info("Last visible video no longer exists");
|
||||
logger.info("Last visible video no longer exists");
|
||||
thumbs = FilmStrip.getThumbs().remoteThumbs;
|
||||
if (thumbs.length) {
|
||||
let id = getPeerContainerResourceId(thumbs[0]);
|
||||
if (remoteVideos[id]) {
|
||||
console.info("electLastVisibleVideo: " + id);
|
||||
logger.info("electLastVisibleVideo: " + id);
|
||||
return id;
|
||||
}
|
||||
// The RemoteVideo was removed (but the DOM elements may
|
||||
@@ -281,10 +282,10 @@ var VideoLayout = {
|
||||
}
|
||||
|
||||
// Go with local video
|
||||
console.info("Fallback to local video...");
|
||||
logger.info("Fallback to local video...");
|
||||
|
||||
let id = APP.conference.getMyUserId();
|
||||
console.info("electLastVisibleVideo: " + id);
|
||||
logger.info("electLastVisibleVideo: " + id);
|
||||
|
||||
return id;
|
||||
},
|
||||
@@ -341,14 +342,20 @@ var VideoLayout = {
|
||||
* @param id the identifier of the video thumbnail
|
||||
*/
|
||||
handleVideoThumbClicked (id) {
|
||||
var smallVideo = VideoLayout.getSmallVideo(id);
|
||||
if(pinnedId) {
|
||||
var oldSmallVideo = VideoLayout.getSmallVideo(pinnedId);
|
||||
if (oldSmallVideo && !interfaceConfig.filmStripOnly)
|
||||
if (oldSmallVideo && !interfaceConfig.filmStripOnly) {
|
||||
oldSmallVideo.focus(false);
|
||||
// as no pinned event will be sent for local video
|
||||
// and we will unpin old one, lets signal it
|
||||
// otherwise we will just send the new pinned one
|
||||
if (smallVideo.isLocal)
|
||||
eventEmitter.emit(
|
||||
UIEvents.PINNED_ENDPOINT, oldSmallVideo, false);
|
||||
}
|
||||
}
|
||||
|
||||
var smallVideo = VideoLayout.getSmallVideo(id);
|
||||
|
||||
// Unpin if currently pinned.
|
||||
if (pinnedId === id)
|
||||
{
|
||||
@@ -358,6 +365,12 @@ var VideoLayout = {
|
||||
if(smallVideo && smallVideo.hasVideo()) {
|
||||
this.updateLargeVideo(currentDominantSpeaker);
|
||||
}
|
||||
} else {
|
||||
// if there is no currentDominantSpeaker, it can also be
|
||||
// that local participant is the dominant speaker
|
||||
// we should act as a participant has left and was on large
|
||||
// and we should choose somebody (electLastVisibleVideo)
|
||||
this.updateLargeVideo(this.electLastVisibleVideo());
|
||||
}
|
||||
|
||||
eventEmitter.emit(UIEvents.PINNED_ENDPOINT, smallVideo, false);
|
||||
@@ -426,7 +439,7 @@ var VideoLayout = {
|
||||
// FIXME: what does this do???
|
||||
remoteVideoActive(videoElement, resourceJid) {
|
||||
|
||||
console.info(resourceJid + " video is now active", videoElement);
|
||||
logger.info(resourceJid + " video is now active", videoElement);
|
||||
|
||||
VideoLayout.resizeThumbnails(
|
||||
false, false, function() {$(videoElement).show();});
|
||||
@@ -724,11 +737,11 @@ var VideoLayout = {
|
||||
if (resourceJid &&
|
||||
lastNEndpoints.indexOf(resourceJid) < 0 &&
|
||||
localLastNSet.indexOf(resourceJid) < 0) {
|
||||
console.log("Remove from last N", resourceJid);
|
||||
logger.log("Remove from last N", resourceJid);
|
||||
if (smallVideo)
|
||||
smallVideo.showPeerContainer('hide');
|
||||
else if (!APP.conference.isLocalId(resourceJid))
|
||||
console.error("No remote video for: " + resourceJid);
|
||||
logger.error("No remote video for: " + resourceJid);
|
||||
isReceived = false;
|
||||
} else if (resourceJid &&
|
||||
//TOFIX: smallVideo may be undefined
|
||||
@@ -741,7 +754,7 @@ var VideoLayout = {
|
||||
if (smallVideo)
|
||||
smallVideo.showPeerContainer('avatar');
|
||||
else if (!APP.conference.isLocalId(resourceJid))
|
||||
console.error("No remote video for: " + resourceJid);
|
||||
logger.error("No remote video for: " + resourceJid);
|
||||
isReceived = false;
|
||||
}
|
||||
|
||||
@@ -768,7 +781,7 @@ var VideoLayout = {
|
||||
remoteVideo.showPeerContainer('show');
|
||||
|
||||
if (!remoteVideo.isVisible()) {
|
||||
console.log("Add to last N", resourceJid);
|
||||
logger.log("Add to last N", resourceJid);
|
||||
|
||||
remoteVideo.addRemoteStreamElement(remoteVideo.videoStream);
|
||||
|
||||
@@ -869,23 +882,23 @@ var VideoLayout = {
|
||||
removeParticipantContainer (id) {
|
||||
// Unlock large video
|
||||
if (pinnedId === id) {
|
||||
console.info("Focused video owner has left the conference");
|
||||
logger.info("Focused video owner has left the conference");
|
||||
pinnedId = null;
|
||||
}
|
||||
|
||||
if (currentDominantSpeaker === id) {
|
||||
console.info("Dominant speaker has left the conference");
|
||||
logger.info("Dominant speaker has left the conference");
|
||||
currentDominantSpeaker = null;
|
||||
}
|
||||
|
||||
var remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo) {
|
||||
// Remove remote video
|
||||
console.info("Removing remote video: " + id);
|
||||
logger.info("Removing remote video: " + id);
|
||||
delete remoteVideos[id];
|
||||
remoteVideo.remove();
|
||||
} else {
|
||||
console.warn("No remote video for " + id);
|
||||
logger.warn("No remote video for " + id);
|
||||
}
|
||||
|
||||
VideoLayout.resizeThumbnails();
|
||||
@@ -896,12 +909,12 @@ var VideoLayout = {
|
||||
return;
|
||||
}
|
||||
|
||||
console.info("Peer video type changed: ", id, newVideoType);
|
||||
logger.info("Peer video type changed: ", id, newVideoType);
|
||||
|
||||
var smallVideo;
|
||||
if (APP.conference.isLocalId(id)) {
|
||||
if (!localVideoThumbnail) {
|
||||
console.warn("Local video not ready yet");
|
||||
logger.warn("Local video not ready yet");
|
||||
return;
|
||||
}
|
||||
smallVideo = localVideoThumbnail;
|
||||
@@ -925,7 +938,7 @@ var VideoLayout = {
|
||||
if (remoteVideo) {
|
||||
remoteVideo.connectionIndicator.showMore();
|
||||
} else {
|
||||
console.info("Error - no remote video for id: " + id);
|
||||
logger.info("Error - no remote video for id: " + id);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -982,7 +995,7 @@ var VideoLayout = {
|
||||
if (smallVideo) {
|
||||
smallVideo.avatarChanged(avatarUrl);
|
||||
} else {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
"Missed avatar update - no small video yet for " + id
|
||||
);
|
||||
}
|
||||
@@ -1136,12 +1149,9 @@ var VideoLayout = {
|
||||
* video stream is currently HD.
|
||||
*/
|
||||
updateResolutionLabel(isResolutionHD) {
|
||||
let videoResolutionLabel = $("#videoResolutionLabel");
|
||||
let id = 'videoResolutionLabel';
|
||||
|
||||
if (isResolutionHD && !videoResolutionLabel.is(":visible"))
|
||||
videoResolutionLabel.css({display: "block"});
|
||||
else if (!isResolutionHD && videoResolutionLabel.is(":visible"))
|
||||
videoResolutionLabel.css({display: "none"});
|
||||
UIUtil.setVisible(id, isResolutionHD);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* global console */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
import { redirect } from '../util/helpers';
|
||||
|
||||
@@ -45,8 +45,8 @@ export default class ConferenceUrl {
|
||||
*/
|
||||
this.inviteURL
|
||||
= location.protocol + "//" + location.host + location.pathname;
|
||||
console.info("Stored original conference URL: " + this.originalURL);
|
||||
console.info("Conference URL for invites: " + this.inviteURL);
|
||||
logger.info("Stored original conference URL: " + this.originalURL);
|
||||
logger.info("Conference URL for invites: " + this.inviteURL);
|
||||
}
|
||||
/**
|
||||
* Obtains the conference invite URL.
|
||||
@@ -67,7 +67,7 @@ export default class ConferenceUrl {
|
||||
* Reloads the conference using original URL with all of the parameters.
|
||||
*/
|
||||
reload() {
|
||||
console.info("Reloading the conference using URL: " + this.originalURL);
|
||||
logger.info("Reloading the conference using URL: " + this.originalURL);
|
||||
redirect(this.originalURL);
|
||||
}
|
||||
}
|
||||
|
||||
128
modules/analytics/analytics.js
Normal file
128
modules/analytics/analytics.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/* global JitsiMeetJS, config, APP */
|
||||
/**
|
||||
* Load the integration of a third-party analytics API such as Google
|
||||
* Analytics. Since we cannot guarantee the quality of the third-party service
|
||||
* (e.g. their server may take noticeably long time to respond), it is in our
|
||||
* best interest (in the sense that the intergration of the analytics API is
|
||||
* important to us but not enough to allow it to prevent people from joining
|
||||
* a conference) to download the API asynchronously. Additionally, Google
|
||||
* Analytics will download its implementation asynchronously anyway so it makes
|
||||
* sense to append the loading on our side rather than prepend it.
|
||||
* @param {string} url the url to be loaded
|
||||
* @returns {Promise} resolved with no arguments when the script is loaded and
|
||||
* rejected with the error from JitsiMeetJS.ScriptUtil.loadScript method
|
||||
*/
|
||||
function loadScript(url) {
|
||||
return new Promise((resolve, reject) =>
|
||||
JitsiMeetJS.util.ScriptUtil.loadScript(
|
||||
url,
|
||||
/* async */ true,
|
||||
/* prepend */ false,
|
||||
/* relativeURL */ false,
|
||||
/* loadCallback */ () => resolve(),
|
||||
/* errorCallback */ error => reject(error)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the initialization of analytics.
|
||||
*/
|
||||
class Analytics {
|
||||
constructor() {
|
||||
this._scriptURLs = Array.isArray(config.analyticsScriptUrls)
|
||||
? config.analyticsScriptUrls : [];
|
||||
this._enabled = !!this._scriptURLs.length
|
||||
&& !config.disableThirdPartyRequests;
|
||||
window.analyticsHandlers = [];
|
||||
const machineId = JitsiMeetJS.getMachineId();
|
||||
this._handlerConstructorOptions = {
|
||||
product: "lib-jitsi-meet",
|
||||
version: JitsiMeetJS.version,
|
||||
session: machineId,
|
||||
user: "uid-" + machineId
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether analytics is enabled or not.
|
||||
* @returns {boolean} whether analytics is enabled or not.
|
||||
*/
|
||||
isEnabled() {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to load the scripts for the analytics handlers.
|
||||
* @returns {Promise} resolves with the handlers that have been
|
||||
* successfully loaded and rejects if there are no handlers loaded or the
|
||||
* analytics is disabled.
|
||||
*/
|
||||
_loadHandlers() {
|
||||
if(!this.isEnabled()) {
|
||||
return Promise.reject(new Error("Analytics is disabled!"));
|
||||
}
|
||||
let handlersPromises = [];
|
||||
this._scriptURLs.forEach(url =>
|
||||
handlersPromises.push(
|
||||
loadScript(url).then(
|
||||
() => {
|
||||
return {type: "success"};
|
||||
},
|
||||
error => {
|
||||
return {type: "error", error, url};
|
||||
}))
|
||||
);
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
Promise.all(handlersPromises).then(values => {
|
||||
values.forEach(el => {
|
||||
if(el.type === "error") {
|
||||
console.log("Fialed to load " + el.url);
|
||||
console.error(el.error);
|
||||
}
|
||||
});
|
||||
|
||||
if(window.analyticsHandlers.length === 0) {
|
||||
reject(new Error("No analytics handlers available"));
|
||||
} else {
|
||||
let handlerInstances = [];
|
||||
window.analyticsHandlers.forEach(
|
||||
Handler => handlerInstances.push(
|
||||
new Handler(this._handlerConstructorOptions)));
|
||||
resolve(handlerInstances);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the analytics scripts and inits JitsiMeetJS.analytics by setting
|
||||
* permanent properties and setting the handlers from the loaded scripts.
|
||||
* NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
|
||||
* null.
|
||||
*/
|
||||
init() {
|
||||
let analytics = JitsiMeetJS.analytics;
|
||||
if(!this.isEnabled() || !analytics)
|
||||
return;
|
||||
|
||||
this._loadHandlers()
|
||||
.then(handlers => {
|
||||
let permanentProperties = {
|
||||
userAgent: navigator.userAgent,
|
||||
roomName: APP.conference.roomName
|
||||
};
|
||||
let {server, group} = APP.tokenData;
|
||||
if(server) {
|
||||
permanentProperties.server = server;
|
||||
}
|
||||
if(group) {
|
||||
permanentProperties.group = group;
|
||||
}
|
||||
analytics.addPermanentProperties(permanentProperties);
|
||||
analytics.setAnalyticsHandlers(handlers);
|
||||
}, error => analytics.dispose() && console.error(error));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default new Analytics();
|
||||
@@ -1,3 +1,5 @@
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
var JSSHA = require('jssha');
|
||||
|
||||
module.exports = {
|
||||
@@ -22,7 +24,7 @@ module.exports = {
|
||||
var attemptFirstAddress;
|
||||
|
||||
config.bosh = config.boshList[idx];
|
||||
console.log('Setting config.bosh to ' + config.bosh +
|
||||
logger.log('Setting config.bosh to ' + config.bosh +
|
||||
' (idx=' + idx + ')');
|
||||
|
||||
if (config.boshAttemptFirstList &&
|
||||
@@ -34,10 +36,10 @@ module.exports = {
|
||||
|
||||
if (attemptFirstAddress != config.bosh) {
|
||||
config.boshAttemptFirst = attemptFirstAddress;
|
||||
console.log('Setting config.boshAttemptFirst=' +
|
||||
logger.log('Setting config.boshAttemptFirst=' +
|
||||
attemptFirstAddress + ' (idx=' + idx + ')');
|
||||
} else {
|
||||
console.log('Not setting boshAttemptFirst, address matches.');
|
||||
logger.log('Not setting boshAttemptFirst, address matches.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user