Compare commits

..

145 Commits

Author SHA1 Message Date
paweldomas
cf83b4142a ref(config): move loggingConfig to config.js 2016-12-01 16:59:39 -06:00
yanas
75b3bc6190 Merge pull request #1176 from jitsi/net_or_infra
Add 'isNetworkFailure' argument to PageReloadOverlay
2016-12-01 16:57:39 -06:00
paweldomas
6c716bcbb1 fix(conference.js): handle CONNECTION_DROPPED_ERROR 2016-12-01 15:55:00 -06:00
paweldomas
44beed6216 feat: distinguish between network and infra... failure 2016-12-01 11:38:44 -06:00
paweldomas
2352811c20 chore(package.json): use fixed version of Strophe
There was functionality added to lib-jitsi-meet that depends on
particular version of Strophe. It could be possibly broken without
testing the update.
2016-12-01 11:38:44 -06:00
Lyubomir Marinov
c1df375af4 Extend ./react/.eslintrc.js from ./.eslintrc.js 2016-12-01 08:30:35 -06:00
Дамян Минков
e8c631de01 Merge pull request #1174 from jitsi/fix-disabled-welcome-page
Fix disabled Welcome page broken with the introduction of React
2016-11-30 21:49:25 -06:00
Lyubomir Marinov
bdc67201e2 Fix disabled Welcome page broken with the introduction of React
The React-based rewrite looks whether there's a room name (in the
window's location) in order to choose between WelcomePage and
Conference. But app.js expects Conference to be rendered before it
builds a room name if WelcomePage is disabled and there's no room name.
A quick and dirty workaround is to render Conference within WelcomePage
so that the rendered result closely resembles index.html before the
React-based rewrite.
2016-11-30 19:54:09 -06:00
Lyubomir Marinov
0db33bb45c React propTypes as static class properties 2016-11-30 19:53:40 -06:00
Дамян Минков
9f26270a98 Merge pull request #1169 from jitsi/page_reload_reason
Log more details on page reload
2016-11-30 15:25:09 -06:00
paweldomas
df721cbd2e feat(analytics): add reason as label to page reload event 2016-11-30 14:30:44 -06:00
hristoterezov
8745efb81f Merge pull request #1158 from jitsi/log_collector
Log collector
2016-11-30 13:07:18 -06:00
yanas
e56f1a9ded Merge pull request #1167 from jitsi/fix_anonymous_domain
Fix the UI when anonymous domain auth is in use
2016-11-30 10:51:24 -06:00
Lyubomir Marinov
52fbb8f02c [RN] Fix React.PropTypes warning 2016-11-30 10:06:29 -06:00
Lyubomir Marinov
a1639b67a5 [RN] Don't display background colors underneath text on WelcomePage 2016-11-30 10:00:59 -06:00
paweldomas
3475ad4674 ref(LogCollector): adapts to caching in LogCollector 2016-11-30 07:38:39 -06:00
damencho
685d117a91 Fixes custom cert and key files for apache config. 2016-11-29 23:54:19 -06:00
damencho
e51f791ab0 Configures to use apache when this is the available web server. 2016-11-29 23:11:15 -06:00
yanas
0f2ba1cefe refactor(UIUtils): merges show and hide functions and cleans visibility setting 2016-11-29 15:07:18 -06:00
Lyubomir Marinov
1f457dfca5 Hyperlinks to legalese such as Privacy Policy and Terms of Service 2016-11-29 14:30:58 -06:00
Paweł Domas
841050953f Merge pull request #1172 from bgrozev/enable-tab-sharing
feat: Enables by default tab sharing for chrome.
2016-11-29 14:08:38 -06:00
Дамян Минков
c6296821c0 Merge pull request #1164 from gerfigna/patch-1
Update api.md. There is still work to be done, cause handling parameters in executeCommand is not currently correct and needs fixing. But for now displayname is the only command that requires a parameter.
2016-11-29 13:18:55 -06:00
paweldomas
7c8ca45d9a ref(LogCollector): extract JitsiMeetLogStorage 2016-11-29 11:30:37 -06:00
Boris Grozev
142f6e4518 feat: Enables by default tab sharing for chrome. 2016-11-29 11:30:02 -06:00
Lyubomir Marinov
f72e7ffbc2 Fix ESLint errors 2016-11-28 20:07:10 -06:00
Lyubomir Marinov
111b6e1c27 React Native 0.38.0, React 15.4.1 2016-11-28 20:07:10 -06:00
Дамян Минков
4add2d0590 Merge pull request #1168 from jitsi/exclude_build_dir
Add 'build' dir to jshintignore
2016-11-28 16:16:38 -06:00
Дамян Минков
cb0f7417b6 Merge pull request #1166 from jitsi/fix-reload-overlay-layout
fix(PageReloadOverlay):Basic layout fix
2016-11-28 16:00:35 -06:00
paweldomas
06eb7c6109 fix(jshintignore): exclude 'build' dir 2016-11-28 15:48:07 -06:00
damencho
4d0701cfda Fixes build. Wrong changelog file. 2016-11-28 14:18:23 -06:00
Дамян Минков
86bce1e5f6 Merge pull request #1152 from jitsi/deb-update
Updates debian packaging.
2016-11-28 13:45:51 -06:00
damencho
8da0d3a1f1 Removes dependencies to other components.
Now the web app can be installed separately from jicofo and jitsi-videobridge, or can be installed on machine running nginx or apache. Currently only nginx will be configured and apache config is left to user. Later we can add and the apache config. Renames jitsi-meet to jitsi-meet-web (just the web content) and jitsi-meet-web-config (configuring jetty, nginx or apache). A new jitsi-meet package will be introduced, a meta package depending on jicofo, jvb and the current packages.
2016-11-28 13:13:08 -06:00
hristoterezov
f32438b219 Merge pull request #1161 from jitsi/pinning-local-not-signal-unpin
Sending unpin after clicking local video and unpinning remote.
2016-11-28 12:06:56 -06:00
paweldomas
0238a10a4b fix(MessageHandler): hide the close button when 'persistent' 2016-11-28 11:05:18 -06:00
paweldomas
6669a96fd8 fix(Toolbar.js): hide recording and SIP buttons from the start 2016-11-28 11:05:18 -06:00
paweldomas
09406bfbfc fix(Toolbar): move login buttons to Profile
Authentication buttons no longer belong to the Toolbar.
2016-11-28 11:05:18 -06:00
paweldomas
51da40e90c ref(UIUtil): add showOrHideElement 2016-11-28 11:05:18 -06:00
paweldomas
52847bd28d fix(conference): crash with anonymous domain config 2016-11-28 11:05:18 -06:00
yanas
835d3c6a25 fix(PageReloadOverlay):Basic layout fix 2016-11-28 10:08:47 -06:00
Germán Figna
00e6e98a61 Update api.md 2016-11-24 11:34:24 +01:00
Lyubomir Marinov
6d90adcdf6 Fix make failure caused by npm link 2016-11-24 02:21:21 -06:00
Ilya Daynatovich
06d2fb0aca Optimize React in production 2016-11-24 02:21:21 -06:00
Ilya Daynatovich
c3428e8213 Split React components out of index.html 2016-11-24 02:21:02 -06:00
hristoterezov
57b0736ebb Merge pull request #1160 from jitsi/fix-unpinning-local-dominant-speaker
Fixes unpinning local user which is dominant speaker.
2016-11-23 17:40:47 -06:00
damencho
6211566c0c Sending unpin after clicking local video and unpinning remote.
If we:
 - pin a remote and click it, unpin is signalled.
 - pin a remote and the click another remote, the new one is pinned and signalled.
 - pin a remote and then click local. UI pins local, but unpinning remote is not signaled, fix addressed with this commit.
 - pin/unpin local, nothing is signalled.
2016-11-23 17:02:24 -06:00
Ilya Daynatovich
48bb427f71 The Makefile file format requires tab characters 2016-11-23 15:54:03 -06:00
hristoterezov
56f15356c7 Merge pull request #1159 from jitsi/non-focusable-close-toastr
Makes close button non-focusable.
2016-11-23 15:41:11 -06:00
damencho
8e6fd0ca95 Fixes unpinning local user which is dominant speaker.
It was not switching and staying on local video on unpinning, after change the last shown video will be used to switch to it.
2016-11-23 15:35:03 -06:00
damencho
b5dfc2a520 Makes close button non-focusable.
Prevents the close button to take focus while user clicks tab in the page, which will privent the toast to be closed.
2016-11-23 14:48:15 -06:00
Дамян Минков
4900fe020d Merge pull request #1156 from BeatC/fix-popover
Fix popover
2016-11-23 12:52:50 -06:00
paweldomas
94bd6bc330 feat(logging_config): add "disableLogCollector" option 2016-11-23 11:32:58 -06:00
paweldomas
36bcc6831b feat: use LogCollector to capture JS console logs 2016-11-23 11:32:58 -06:00
paweldomas
76c89845a8 feat: add logging config 2016-11-23 11:32:58 -06:00
paweldomas
b58f1cdd16 use logger instead of console 2016-11-23 11:32:55 -06:00
Ilya Daynatovich
141c64cd00 Add new variable 2016-11-23 12:32:59 +02:00
Ilya Daynatovich
51b802da84 fix problem with popover 2016-11-23 12:27:34 +02:00
yanas
71c27f308c Merge pull request #1155 from jitsi/removes-click-listeners
Removes click handlers when popup is hidden.
2016-11-22 17:33:30 -06:00
damencho
75b9adf01b Updates comments. 2016-11-22 17:31:01 -06:00
damencho
a079914603 Removes click handlers when popup is hidden. 2016-11-22 17:06:19 -06:00
yanas
4d3ca4a85a Merge pull request #1148 from jitsi/analytics
feat(Analytics): Multiple analytics handlers support
2016-11-22 13:53:02 -06:00
Lyubomir Marinov
afa1d5423c Merge branch 'prepare-for-react-1' 2016-11-21 21:00:13 -06:00
Ilya Daynatovich
766eb94c7d Prepare for React: Use Haste resolver for Web
In preparation for and as another early step in rewriting the Web
version of jitsi-meet using React, use Haste resolver which is able to
distinguish among platform-independent files, Web-specific and
mobile-specific ones.

Additionally, (1) make sure that Babel is capable of understanding React
files and (2) introduce React as a dependency.

The purpose is to repeatedly take small steps towards our goal and merge
them before they get in conflict with the separate ongoing advancement
of the Web version of jitsi-meet.
2016-11-21 20:26:50 -06:00
Дамян Минков
ad6e793615 Merge pull request #1146 from jitsi/adorable-io-avatars
fix: replace robohash avatars with adorable io
2016-11-21 10:00:57 -06:00
Paweł Domas
d900d3c3fd Merge pull request #1149 from jitsi/ss_resize
Fixes issue with not resizing properly if SS is on and the filmstrip is hidden
2016-11-18 12:42:11 -06:00
hristoterezov
7f315ef105 fix(VideoLayout): Issue with not resizing properly if SS is on and the filmstrip is hidden 2016-11-18 11:26:33 -06:00
hristoterezov
dc0a7e7628 feat(Analytics): Multiple analytics handlers support 2016-11-16 16:36:32 -06:00
yanas
6d1f42bf30 Merge pull request #1115 from jitsi/remove_css_classes
Removes unused css classes
2016-11-16 13:00:26 -06:00
yanas
c26b144f0d Merge pull request #1144 from kkrisstoff/chat-animation-fix
Chat animation fix
2016-11-16 12:45:40 -06:00
yanas
752f4dd5de Merge pull request #1141 from kkrisstoff/404-link-color
link class added
2016-11-16 11:24:48 -06:00
yanas
693ebbea9d Merge pull request #1143 from BeatC/visual-problems
Fix some ui bugs
2016-11-16 11:23:29 -06:00
yanas
b24a54aab2 fix: replace robohash avatars with adorable io 2016-11-16 11:06:25 -06:00
Konstantyn Pahsura
00aee89709 doc added 2016-11-16 14:09:22 +02:00
Дамян Минков
a5f243e18d Merge pull request #1142 from jitsi/fix-ff-desktop-sharing-message
fix: Firefox desktop sharing extension required dialog
2016-11-15 13:48:17 -06:00
yanas
d05ff9b4ee fix: Firefox desktop sharing extension required dialog 2016-11-15 12:41:24 -06:00
Konstantyn Pahsura
a67087b6de focus for chat changes 2016-11-15 20:18:40 +02:00
Ilya Daynatovich
e2ea16ea3f Fix some ui bugs 2016-11-15 16:37:09 +02:00
yanas
5098b64666 Merge pull request #1137 from BeatC/thumbnail-avatars
Thumbnail avatars
2016-11-14 17:47:59 -06:00
hristoterezov
66fbc28385 Merge branch 'kkrisstoff-add/tip-randomiser' 2016-11-14 15:02:58 -06:00
hristoterezov
4bcd75f15c refactor(close_pages): Refactor the close pages. 2016-11-14 15:02:27 -06:00
Konstantyn Pahsura
da6af88910 fixes and changes 2016-11-14 15:02:27 -06:00
Konstantyn Pahsura
1a91f4953b tip randomiser added 2016-11-14 15:02:27 -06:00
yanas
9a0d28720d Merge pull request #1139 from BeatC/FIX-adjust-branding1
Fix visual bugs in sidebar
2016-11-14 14:26:21 -06:00
hristoterezov
5b6956e25b Merge pull request #1101 from jitsi/stop_media_when_xmpp_drops
Stop the media when XMPP connection is dropped
2016-11-14 13:06:53 -06:00
Lyubomir Marinov
fd51108ae3 [iOS] Remove unnecessary CODE_SIGN_IDENTITY 2016-11-14 08:44:29 -06:00
Lyubomir Marinov
73a2eca51c [iOS] Strip unwanted architectures from embedded frameworks 2016-11-14 08:32:47 -06:00
Ilya Daynatovich
9bc24e1caa Fix aligning of indicator icon; Update logic for dynamically change of thumb indicators via font-size 2016-11-14 12:45:28 +02:00
Konstantyn Pahsura
3fc02bf6c2 link class added 2016-11-14 12:42:01 +02:00
Ilya Daynatovich
3bd4f1d5d8 Updated layout 2016-11-14 11:09:07 +02:00
Ilya Daynatovich
f3dbeea091 Make filmstrip indicators to resize dynamically 2016-11-14 11:09:07 +02:00
Ilya Daynatovich
d2ef94a7eb Fix problem with hint 2016-11-14 11:02:11 +02:00
Ilya Daynatovich
1d1d8defda Updated calculation of offset 2016-11-14 11:01:50 +02:00
Ilya Daynatovich
d0127b879d fixed dropdown colors 2016-11-14 11:01:50 +02:00
Ilya Daynatovich
cbc6943305 work on colors 2016-11-14 11:01:50 +02:00
Maxim Voloshin
9124aa2c87 Adjusted CSS for side toolbar elements 2016-11-14 11:01:50 +02:00
Lyubomir Marinov
8817f0c53d [iOS] Prepare for App Store release 2016-11-13 18:45:40 -06:00
Lyubomir Marinov
e4f9c17f8a [iOS] Prepare for App Store release 2016-11-13 18:27:23 -06:00
yanas
686ee1111a Merge pull request #1129 from BeatC/make-identical-text-input
Make identical text input
2016-11-11 15:45:46 -06:00
bgrozev
4b11767ac5 Merge pull request #1140 from jitsi/fix-desktop-sharing-screen-size
fix: desktop streming screen size
2016-11-11 13:53:39 -06:00
yanas
5545c0d905 fix: desktop streming screen size 2016-11-11 13:26:07 -06:00
bgrozev
611edf7e34 Merge pull request #1134 from jitsi/cosmetic-changes
Comment and empty lines removed
2016-11-11 13:18:41 -06:00
Lyubomir Marinov
7a37d70fb6 React Native 0.37.0 2016-11-11 11:57:25 -06:00
yanas
b2577090bd Merge pull request #1135 from BeatC/fix-js-from-styles-editions
Editions to "clean css from js"
2016-11-11 10:18:49 -06:00
Ilya Daynatovich
5b0777d4db Made inputs identical 2016-11-11 17:22:47 +02:00
Ilya Daynatovich
12c1574f07 renamed files 2016-11-11 17:13:18 +02:00
Ilya Daynatovich
5623a06996 renamed input-control block to form-control 2016-11-11 17:13:18 +02:00
Ilya Daynatovich
148960c6d2 made editions 2016-11-11 12:27:29 +02:00
yanas
ff8c6690ef Comment and empty lines removed 2016-11-10 17:27:19 -06:00
yanas
c926e95822 Merge pull request #1133 from jitsi/fix-tip-text-close-page
Modifies tip text in close page
2016-11-10 17:24:43 -06:00
yanas
0a28dd0cd3 Modifies tip text in close page 2016-11-10 17:02:34 -06:00
yanas
8caae4bfde Merge pull request #1111 from BeatC/FIX-clean-js-from-styles-1
Fix clean js from styles 1
2016-11-10 15:40:07 -06:00
yanas
a67c5a8dc7 Merge pull request #1108 from bgrozev/restrict-eslint-versions
chore: Only uses jslint 3+
2016-11-10 14:45:29 -06:00
yanas
cf38fde207 Updates to >= to match versions of 3+ 2016-11-10 14:20:30 -06:00
hristoterezov
4549b766f5 Merge pull request #1131 from jitsi/suspended-detection
Suspended detection
2016-11-10 13:45:14 -06:00
yanas
45126d4f3d Merge pull request #1132 from jitsi/calculate-correct-size-for-thumbnails
Calculate correct size for thumbnails
2016-11-10 13:17:32 -06:00
damencho
82926ef8c6 Detects suspended event, stops local video and shows overlay.
Also removes device change listener, cause when PC wakeups devices will be reconnected and we can try open the local video again.
2016-11-10 13:17:23 -06:00
yanas
42604971dc Merge pull request #1125 from BeatC/small-avatar-images
Fixed problem with resizing thumb avatars
2016-11-10 13:12:03 -06:00
yanas
95fcf5bae5 Change method name to fit better its purpose 2016-11-10 11:14:31 -06:00
Ilya Daynatovich
34acadc3b5 Rename method 2016-11-10 11:14:31 -06:00
Ilya Daynatovich
d3df082e3d Fix thumbnail overflow 2016-11-10 11:13:31 -06:00
Yana Stamcheva
fe7e9f333f [iOS] Fix launch screen text 2016-11-10 10:48:30 -06:00
Дамян Минков
92901e09e1 Merge pull request #1128 from BeatC/fix-toggle-filmstrip-shortcut
Moved keyboard initialization to filmstrip toolbar
2016-11-10 10:30:59 -06:00
Ilya Daynatovich
128b301a39 Fix the tests 2016-11-10 14:45:42 +02:00
Ilya Daynatovich
1b1b9475a4 Clean up js from styles 2016-11-10 13:32:12 +02:00
Ilya Daynatovich
5aff96e3b7 Updated in videolayout 2016-11-10 13:32:12 +02:00
Ilya Daynatovich
fb4e9b3c6d Work on fixing the tests 2016-11-10 13:32:12 +02:00
Ilya Daynatovich
a8a6b38c28 Updated method for showing/hiding elements 2016-11-10 13:32:12 +02:00
Maxim Voloshin
68ab87cc0d Hide DOM elements using css class 2016-11-10 13:32:12 +02:00
Ilya Daynatovich
986c29ca5d updated filmstrip handler 2016-11-10 12:18:33 +02:00
Yana Stamcheva
d7fc20b607 [iOS] Center launch screen text 2016-11-09 19:58:48 -06:00
damencho
96b280668d Adds suspend overlay. 2016-11-09 16:32:09 -06:00
Lyubomir Marinov
66b7404961 [iOS] Try to fix the launch screen 2016-11-09 15:06:07 -06:00
hristoterezov
7f3323f7c0 Merge pull request #1130 from jitsi/fix-stopping-sharedvideo
Stops player update before sending stopping of shared video.
2016-11-09 14:20:38 -06:00
damencho
e34d86b485 Stops player update before sending stopping of shared video.
We used to stop player updates on self presence received, so between stop and self presence we can send a playing update which will provoke adding the video again to other participants.
2016-11-09 12:42:47 -06:00
Lyubomir Marinov
34ea330aa3 [iOS] Try to fix the launch screen
The launch screen appears not centered and/or clipped on certain
devices. Unfortunately, I cannot reproduce it when I deploy the app to
devices and Simulator from Xcode 8.1. It may (or may very well not) be
that the Xcode version matters and the enterprise build server does
appear to use an older Xcode version.
2016-11-09 12:41:20 -06:00
Дамян Минков
70c3c1a21c Merge pull request #1102 from jitsi/limit_display_name
Limit long display names
2016-11-09 10:51:46 -06:00
hristoterezov
98d3755859 Merge pull request #1121 from jitsi/fix-two-panels-shown
Hides all side panels before showing new one.
2016-11-09 10:42:49 -06:00
hristoterezov
a4a1579c84 style(conference): Rename MAX_DISPLAYNAME_LENGTH 2016-11-09 10:22:43 -06:00
Ilya Daynatovich
20c6dba599 Moved keyboard initialization to filmstrip toolbar; Replaced toggle filmstrip button from extended toolbar 2016-11-09 12:41:23 +02:00
Ilya Daynatovich
f09a9be523 Fixed problem with resizing thumb avatars 2016-11-08 13:36:43 +02:00
damencho
91340a5268 Hides all side panels before showing new one. 2016-11-07 14:30:02 -06:00
hristoterezov
c41c219206 fix(Thumbnails): removes unused css classes 2016-11-04 15:24:05 -05:00
Boris Grozev
16a2b0377a chore: Only uses jslint 3+
because older versions don't work with our .jslintrc file
2016-11-03 13:18:56 -05:00
hristoterezov
b1f129a53a fix(Chat): Display long nicknames with ... 2016-11-01 16:41:58 -05:00
hristoterezov
a6a7e81a0f feat(DisplayName): Limit local and remote display name to 50 chars 2016-11-01 16:40:52 -05:00
paweldomas
d60146c6a8 fix(conference): leave the room when XMPP connection is dropped
It looks weird when the page reload overlay appears and the conference
continues in the background (the connection to the JVB remains active).
The library will not recover and the conference can not continue without
the signalling, so the room should be left and media stopped.
2016-11-01 15:08:59 -05:00
148 changed files with 3147 additions and 1567 deletions

View File

@@ -8,3 +8,6 @@ indent_size = 4
indent_style = space
max_line_length = 80
trim_trailing_whitespace = true
[Makefile]
indent_style = tab

View File

@@ -1,3 +1,4 @@
build/
debian/
libs/
node_modules/

View File

@@ -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>

View File

@@ -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
View File

@@ -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();
});

View File

@@ -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
View 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;

View File

@@ -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>

View File

@@ -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);
}
},
/**

View File

@@ -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'
};

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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;
}
/**

View File

@@ -92,8 +92,9 @@
}
#toast-container.notification-bottom-right {
$videoOffset: 2 * ($thumbnailVideoMargin + $thumbnailsBorder) + $thumbnailVideoBorder;
bottom: 135px;
right: 28px;
right: $hideFilmstripButtonWidth + $videoOffset;
}
#toast-container * {

View File

@@ -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
View 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;
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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;
}

View 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
View 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);
}
}

View File

@@ -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';

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -13,5 +13,4 @@
#reloadProgressBar {
width: 180px;
margin: 5px auto;
}
}

View File

@@ -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
View File

@@ -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
View File

@@ -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.

View File

@@ -1,4 +0,0 @@
#!/bin/sh -e
# Source debconf library.
. /usr/share/debconf/confmodule

View File

@@ -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
;;

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -52,6 +52,8 @@ case "$1" in
;;
purge)
# Clear the debconf variable
db_purge
;;
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)

View File

@@ -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

View File

@@ -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)
;;

View File

@@ -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.

View File

@@ -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

View File

@@ -1 +1 @@
[type: gettext/rfc822deb] jitsi-meet.templates
[type: gettext/rfc822deb] jitsi-meet-web-config.templates

View File

@@ -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 ""

View File

@@ -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.
```

View File

@@ -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;

View 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>

View File

@@ -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">

View File

@@ -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

View File

@@ -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

View File

@@ -36,6 +36,8 @@
</dict>
</array>
</dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@@ -5,6 +5,10 @@
{
"appID": "BQNXB4G3KQ.org.jitsi.JitsiMeet.ios",
"paths": [ "*" ]
},
{
"appID": "UPXU4CQZ5P.com.atlassian.JitsiMeet.ios",
"paths": [ "*" ]
}
]
}

View File

@@ -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;

View File

@@ -79,6 +79,10 @@
"policyText": "&nbsp;",
"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",

View File

@@ -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);
}
}

View File

@@ -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];

View File

@@ -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;
}

View File

@@ -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">&times;</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.
*/

View File

@@ -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});

View File

@@ -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(

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>`;

View File

@@ -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) {

View File

@@ -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');
}
}
});

View File

@@ -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>`

View File

@@ -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);
}
);
},

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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();
}
},
/**

View File

@@ -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';

View File

@@ -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 : '');
}
};

View File

@@ -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'));
},
/**

View 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();
}
};

View File

@@ -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);
},
/**

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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;
}
};

View File

@@ -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

View File

@@ -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"});
}
}

View File

@@ -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;

View File

@@ -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';

View File

@@ -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);
};
/**

View File

@@ -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,

View File

@@ -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);
},
/**

View File

@@ -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);
}
}

View 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();

View File

@@ -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