Browse Source

feat(eslint): Enable for non react files

master
hristoterezov 7 years ago
parent
commit
969f5d67ab
55 changed files with 3599 additions and 2698 deletions
  1. 261
    11
      .eslintrc.js
  2. 2
    2
      ConferenceEvents.js
  3. 36
    29
      analytics.js
  4. 438
    260
      conference.js
  5. 55
    50
      config.js
  6. 37
    20
      connection.js
  7. 2
    2
      index.html
  8. 32
    20
      interface_config.js
  9. 9
    4
      logging_config.js
  10. 109
    62
      modules/FollowMe.js
  11. 228
    203
      modules/UI/UI.js
  12. 1
    1
      modules/UI/UIErrors.js
  13. 23
    19
      modules/UI/audio_levels/AudioLevels.js
  14. 87
    66
      modules/UI/authentication/AuthHandler.js
  15. 48
    38
      modules/UI/authentication/LoginDialog.js
  16. 17
    13
      modules/UI/avatar/Avatar.js
  17. 81
    43
      modules/UI/etherpad/Etherpad.js
  18. 97
    75
      modules/UI/recording/Recording.js
  19. 215
    148
      modules/UI/shared_video/SharedVideo.js
  20. 25
    16
      modules/UI/shared_video/SharedVideoThumb.js
  21. 48
    30
      modules/UI/side_pannels/SideContainerToggler.js
  22. 1
    1
      modules/UI/side_pannels/SidePanels.js
  23. 120
    89
      modules/UI/side_pannels/chat/Chat.js
  24. 16
    10
      modules/UI/side_pannels/chat/Commands.js
  25. 20
    21
      modules/UI/side_pannels/chat/Replacement.js
  26. 21
    21
      modules/UI/side_pannels/chat/smileys.js
  27. 3
    5
      modules/UI/side_pannels/contactlist/ContactListView.js
  28. 73
    53
      modules/UI/side_pannels/profile/Profile.js
  29. 58
    40
      modules/UI/side_pannels/settings/SettingsMenu.js
  30. 117
    84
      modules/UI/util/MessageHandler.js
  31. 59
    41
      modules/UI/util/UIUtil.js
  32. 83
    59
      modules/UI/videolayout/Filmstrip.js
  33. 11
    10
      modules/UI/videolayout/LargeContainer.js
  34. 86
    56
      modules/UI/videolayout/LargeVideoManager.js
  35. 48
    38
      modules/UI/videolayout/LocalVideo.js
  36. 97
    74
      modules/UI/videolayout/RemoteVideo.js
  37. 119
    102
      modules/UI/videolayout/SmallVideo.js
  38. 100
    60
      modules/UI/videolayout/VideoContainer.js
  39. 273
    202
      modules/UI/videolayout/VideoLayout.js
  40. 4
    4
      modules/URL/ConferenceUrl.js
  41. 58
    48
      modules/devices/mediaDeviceHelper.js
  42. 115
    105
      modules/keyboardshortcut/keyboardshortcut.js
  43. 63
    60
      modules/keycode/keycode.js
  44. 7
    3
      modules/recorder/Recorder.js
  45. 52
    44
      modules/settings/Settings.js
  46. 24
    2
      modules/translation/translation.js
  47. 1
    0
      modules/transport/PostMessageTransportBackend.js
  48. 2
    0
      modules/util/JitsiLocalStorage.js
  49. 7
    5
      modules/util/JitsiMeetLogStorage.js
  50. 2
    2
      modules/util/helpers.js
  51. 0
    259
      react/.eslintrc.js
  52. 52
    43
      service/UI/UIEvents.js
  53. 18
    18
      service/remotecontrol/Constants.js
  54. 22
    18
      static/close.js
  55. 16
    9
      webpack.config.js

+ 261
- 11
.eslintrc.js View File

23
         'sourceType': 'module'
23
         'sourceType': 'module'
24
     },
24
     },
25
     'plugins': [
25
     'plugins': [
26
-        'flowtype'
26
+        'flowtype',
27
+
28
+        // ESLint's rule no-duplicate-imports does not understand Flow's import
29
+        // type. Fortunately, eslint-plugin-import understands Flow's import
30
+        // type.
31
+        'import'
27
     ],
32
     ],
28
     'rules': {
33
     'rules': {
34
+        // Possible Errors group
35
+        'no-cond-assign': 2,
36
+        'no-console': 0,
37
+        'no-constant-condition': 2,
38
+        'no-control-regex': 2,
39
+        'no-debugger': 2,
40
+        'no-dupe-args': 2,
41
+        'no-dupe-keys': 2,
42
+        'no-duplicate-case': 2,
43
+        'no-empty': 2,
44
+        'no-empty-character-class': 2,
45
+        'no-ex-assign': 2,
46
+        'no-extra-boolean-cast': 2,
47
+        'no-extra-parens': [
48
+            'error',
49
+            'all',
50
+            { 'nestedBinaryExpressions': false }
51
+        ],
52
+        'no-extra-semi': 2,
53
+        'no-func-assign': 2,
54
+        'no-inner-declarations': 2,
55
+        'no-invalid-regexp': 2,
56
+        'no-irregular-whitespace': 2,
57
+        'no-negated-in-lhs': 2,
58
+        'no-obj-calls': 2,
59
+        'no-prototype-builtins': 0,
60
+        'no-regex-spaces': 2,
61
+        'no-sparse-arrays': 2,
62
+        'no-unexpected-multiline': 2,
63
+        'no-unreachable': 2,
64
+        'no-unsafe-finally': 2,
65
+        'use-isnan': 2,
66
+        'valid-typeof': 2,
67
+
68
+        // Best Practices group
69
+        'accessor-pairs': 0,
70
+        'array-callback-return': 2,
71
+        'block-scoped-var': 0,
72
+        'complexity': 0,
73
+        'consistent-return': 0,
74
+        'curly': 2,
75
+        'default-case': 0,
76
+        'dot-location': [ 'error', 'property' ],
77
+        'dot-notation': 2,
78
+        'eqeqeq': 2,
79
+        'guard-for-in': 2,
80
+        'no-alert': 2,
81
+        'no-caller': 2,
82
+        'no-case-declarations': 2,
83
+        'no-div-regex': 0,
84
+        'no-else-return': 2,
85
+        'no-empty-function': 2,
86
+        'no-empty-pattern': 2,
87
+        'no-eq-null': 2,
88
+        'no-eval': 2,
89
+        'no-extend-native': 2,
90
+        'no-extra-bind': 2,
91
+        'no-extra-label': 2,
92
+        'no-fallthrough': 2,
93
+        'no-floating-decimal': 2,
94
+        'no-implicit-coercion': 2,
95
+        'no-implicit-globals': 2,
96
+        'no-implied-eval': 2,
97
+        'no-invalid-this': 2,
98
+        'no-iterator': 2,
99
+        'no-labels': 2,
100
+        'no-lone-blocks': 2,
101
+        'no-loop-func': 2,
102
+        'no-magic-numbers': 0,
103
+        'no-multi-spaces': 2,
104
+        'no-multi-str': 2,
105
+        'no-native-reassign': 2,
106
+        'no-new': 2,
107
+        'no-new-func': 2,
108
+        'no-new-wrappers': 2,
109
+        'no-octal': 2,
110
+        'no-octal-escape': 2,
111
+        'no-param-reassign': 2,
112
+        'no-proto': 2,
113
+        'no-redeclare': 2,
114
+        'no-return-assign': 2,
115
+        'no-script-url': 2,
116
+        'no-self-assign': 2,
117
+        'no-self-compare': 2,
118
+        'no-sequences': 2,
119
+        'no-throw-literal': 2,
120
+        'no-unmodified-loop-condition': 2,
121
+        'no-unused-expressions': [
122
+            'error',
123
+            {
124
+                'allowShortCircuit': true,
125
+                'allowTernary': true
126
+            }
127
+        ],
128
+        'no-unused-labels': 2,
129
+        'no-useless-call': 2,
130
+        'no-useless-concat': 2,
131
+        'no-useless-escape': 2,
132
+        'no-void': 2,
133
+        'no-warning-comments': 0,
134
+        'no-with': 2,
135
+        'radix': 2,
136
+        'vars-on-top': 2,
137
+        'wrap-iife': [ 'error', 'inside' ],
138
+        'yoda': 2,
139
+
140
+        // Strict Mode group
141
+        'strict': 2,
142
+
143
+        // Variables group
144
+        'init-declarations': 0,
145
+        'no-catch-shadow': 2,
146
+        'no-delete-var': 2,
147
+        'no-label-var': 2,
148
+        'no-restricted-globals': 0,
149
+        'no-shadow': 2,
150
+        'no-shadow-restricted-names': 2,
151
+        'no-undef': 2,
152
+        'no-undef-init': 2,
153
+        'no-undefined': 0,
154
+        'no-unused-vars': 2,
155
+        'no-use-before-define': [ 'error', { 'functions': false } ],
156
+
157
+        // Stylistic issues group
158
+        'array-bracket-spacing': [
159
+            'error',
160
+            'always',
161
+            { 'objectsInArrays': true }
162
+        ],
163
+        'block-spacing': [ 'error', 'always' ],
164
+        'brace-style': 2,
165
+        'camelcase': 2,
166
+        'comma-dangle': 2,
167
+        'comma-spacing': 2,
168
+        'comma-style': 2,
169
+        'computed-property-spacing': 2,
170
+        'consistent-this': [ 'error', 'self' ],
171
+        'eol-last': 2,
172
+        'func-names': 0,
173
+        'func-style': 0,
174
+        'id-blacklist': 0,
175
+        'id-length': 0,
176
+        'id-match': 0,
29
         'indent': [
177
         'indent': [
30
             'error',
178
             'error',
31
             4,
179
             4,
43
                 'SwitchCase': 0
191
                 'SwitchCase': 0
44
             }
192
             }
45
         ],
193
         ],
46
-        'new-cap': [
194
+        'key-spacing': 2,
195
+        'keyword-spacing': 2,
196
+        'linebreak-style': [ 'error', 'unix' ],
197
+        'lines-around-comment': [
47
             'error',
198
             'error',
48
             {
199
             {
49
-                'capIsNew': false // Behave like JSHint's newcap.
200
+                'allowBlockStart': true,
201
+                'allowObjectStart': true,
202
+                'beforeBlockComment': true,
203
+                'beforeLineComment': true
50
             }
204
             }
51
         ],
205
         ],
52
-        // While it is considered a best practice to avoid using methods on
53
-        // console in JavaScript that is designed to be executed in the browser
54
-        // and ESLint includes the rule among its set of recommended rules, (1)
55
-        // the general practice is to strip such calls before pushing to
56
-        // production and (2) we prefer to utilize console in lib-jitsi-meet
57
-        // (and jitsi-meet).
58
-        'no-console': 'off',
59
-        'semi': 'error'
206
+        'max-depth': 2,
207
+        'max-len': [ 'error', 80 ],
208
+        'max-lines': 0,
209
+        'max-nested-callbacks': 2,
210
+        'max-params': 2,
211
+        'max-statements': 0,
212
+        'max-statements-per-line': 2,
213
+        'multiline-ternary': 0,
214
+        'new-cap': 2,
215
+        'new-parens': 2,
216
+        'newline-after-var': 2,
217
+        'newline-before-return': 2,
218
+        'newline-per-chained-call': 2,
219
+        'no-array-constructor': 2,
220
+        'no-bitwise': 2,
221
+        'no-continue': 2,
222
+        'no-inline-comments': 0,
223
+        'no-lonely-if': 2,
224
+        'no-mixed-operators': 2,
225
+        'no-mixed-spaces-and-tabs': 2,
226
+        'no-multiple-empty-lines': 2,
227
+        'no-negated-condition': 2,
228
+        'no-nested-ternary': 0,
229
+        'no-new-object': 2,
230
+        'no-plusplus': 0,
231
+        'no-restricted-syntax': 0,
232
+        'no-spaced-func': 2,
233
+        'no-tabs': 2,
234
+        'no-ternary': 0,
235
+        'no-trailing-spaces': 2,
236
+        'no-underscore-dangle': 0,
237
+        'no-unneeded-ternary': 2,
238
+        'no-whitespace-before-property': 2,
239
+        'object-curly-newline': 0,
240
+        'object-curly-spacing': [ 'error', 'always' ],
241
+        'object-property-newline': 2,
242
+        'one-var': 0,
243
+        'one-var-declaration-per-line': 0,
244
+        'operator-assignment': 0,
245
+        'operator-linebreak': [ 'error', 'before' ],
246
+        'padded-blocks': 0,
247
+        'quote-props': 0,
248
+        'quotes': [ 'error', 'single' ],
249
+        'require-jsdoc': [
250
+            'error',
251
+            {
252
+                'require': {
253
+                    'ClassDeclaration': true,
254
+                    'FunctionDeclaration': true,
255
+                    'MethodDefinition': true
256
+                }
257
+            }
258
+        ],
259
+        'semi': [ 'error', 'always' ],
260
+        'semi-spacing': 2,
261
+        'sort-vars': 2,
262
+        'space-before-blocks': 2,
263
+        'space-before-function-paren': [ 'error', 'never' ],
264
+        'space-in-parens': [ 'error', 'never' ],
265
+        'space-infix-ops': 2,
266
+        'space-unary-ops': 2,
267
+        'spaced-comment': 2,
268
+        'unicode-bom': 0,
269
+        'wrap-regex': 0,
270
+
271
+        // ES6 group rules
272
+        'arrow-body-style': [
273
+            'error',
274
+            'as-needed',
275
+            { requireReturnForObjectLiteral: true }
276
+        ],
277
+        'arrow-parens': [ 'error', 'as-needed' ],
278
+        'arrow-spacing': 2,
279
+        'constructor-super': 2,
280
+        'generator-star-spacing': 2,
281
+        'no-class-assign': 2,
282
+        'no-confusing-arrow': 2,
283
+        'no-const-assign': 2,
284
+        'no-dupe-class-members': 2,
285
+        'no-new-symbol': 2,
286
+        'no-restricted-imports': 0,
287
+        'no-this-before-super': 2,
288
+        'no-useless-computed-key': 2,
289
+        'no-useless-constructor': 2,
290
+        'no-useless-rename': 2,
291
+        'no-var': 2,
292
+        'object-shorthand': [
293
+            'error',
294
+            'always',
295
+            { 'avoidQuotes': true }
296
+        ],
297
+        'prefer-arrow-callback': [ 'error', { 'allowNamedFunctions': true } ],
298
+        'prefer-const': 2,
299
+        'prefer-reflect': 0,
300
+        'prefer-rest-params': 2,
301
+        'prefer-spread': 2,
302
+        'prefer-template': 2,
303
+        'require-yield': 2,
304
+        'rest-spread-spacing': 2,
305
+        'sort-imports': 0,
306
+        'template-curly-spacing': 2,
307
+        'yield-star-spacing': 2,
308
+
309
+        'import/no-duplicates': 2
60
     }
310
     }
61
 };
311
 };

+ 2
- 2
ConferenceEvents.js View File

1
 /**
1
 /**
2
  * Notifies interested parties that hangup procedure will start.
2
  * Notifies interested parties that hangup procedure will start.
3
  */
3
  */
4
-export const BEFORE_HANGUP = "conference.before_hangup";
4
+export const BEFORE_HANGUP = 'conference.before_hangup';
5
 
5
 
6
 /**
6
 /**
7
  * Notifies interested parties that desktop sharing enable/disable state is
7
  * Notifies interested parties that desktop sharing enable/disable state is
8
  * changed.
8
  * changed.
9
  */
9
  */
10
 export const DESKTOP_SHARING_ENABLED_CHANGED
10
 export const DESKTOP_SHARING_ENABLED_CHANGED
11
-    = "conference.desktop_sharing_enabled_changed";
11
+    = 'conference.desktop_sharing_enabled_changed';

+ 36
- 29
analytics.js View File

1
 /* global ga */
1
 /* global ga */
2
 /* eslint-disable indent */
2
 /* eslint-disable indent */
3
 
3
 
4
-(function (ctx) {
5
-  function Analytics() {
6
-    /* eslint-disable semi */
7
-
4
+(function(ctx) {
8
     /**
5
     /**
9
-     * Google Analytics
6
+     *
10
      */
7
      */
11
-    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
12
-        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
13
-    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
14
-    ga('create', 'UA-319188-14', 'jit.si');
15
-    ga('send', 'pageview');
8
+    function Analytics() {
9
+        /* eslint-disable */
10
+
11
+        /**
12
+         * Google Analytics
13
+         */
14
+        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
15
+            (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
16
+        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
17
+        ga('create', 'UA-319188-14', 'jit.si');
18
+        ga('send', 'pageview');
19
+
20
+        /* eslint-enable */
21
+    }
16
 
22
 
17
-    /* eslint-enable semi */
18
-  }
23
+    Analytics.prototype.sendEvent = function(action, data) {
24
+        // empty label if missing value for it and add the value,
25
+        // the value should be integer or null
26
+        let value = data.value;
19
 
27
 
20
-  Analytics.prototype.sendEvent = function (action, data) {
21
-    // empty label if missing value for it and add the value,
22
-    // the value should be integer or null
23
-    var value = data.value;
24
-    value = value? Math.round(parseFloat(value)) : null;
25
-    var label = data.label || "";
28
+        value = value ? Math.round(parseFloat(value)) : null;
29
+        const label = data.label || '';
26
 
30
 
27
-    ga('send', 'event', 'jit.si',
28
-        action + '.' + data.browserName, label, value);
29
-  };
31
+        ga('send', 'event', 'jit.si',
32
+            `${action}.${data.browserName}`, label, value);
33
+    };
30
 
34
 
31
-  if (typeof ctx.JitsiMeetJS === "undefined")
32
-    ctx.JitsiMeetJS = {};
33
-  if (typeof ctx.JitsiMeetJS.app === "undefined")
34
-    ctx.JitsiMeetJS.app = {};
35
-  if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === "undefined")
36
-    ctx.JitsiMeetJS.app.analyticsHandlers = [];
37
-  ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
38
-}(window));
35
+    if (typeof ctx.JitsiMeetJS === 'undefined') {
36
+        ctx.JitsiMeetJS = {};
37
+    }
38
+    if (typeof ctx.JitsiMeetJS.app === 'undefined') {
39
+        ctx.JitsiMeetJS.app = {};
40
+    }
41
+    if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === 'undefined') {
42
+        ctx.JitsiMeetJS.app.analyticsHandlers = [];
43
+    }
44
+    ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
45
+})(window);

+ 438
- 260
conference.js
File diff suppressed because it is too large
View File


+ 55
- 50
config.js View File

1
+/* eslint-disable no-unused-vars, no-var */
1
 var config = { // eslint-disable-line no-unused-vars
2
 var config = { // eslint-disable-line no-unused-vars
2
     // Configuration
3
     // Configuration
3
     //
4
     //
4
 
5
 
5
     // Alternative location for the configuration.
6
     // Alternative location for the configuration.
6
-    //configLocation: './config.json',
7
+    // configLocation: './config.json',
7
 
8
 
8
     // Custom function which given the URL path should return a room name.
9
     // Custom function which given the URL path should return a room name.
9
-    //getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
10
+    // getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
10
 
11
 
11
 
12
 
12
     // Connection
13
     // Connection
17
         domain: 'jitsi-meet.example.com',
18
         domain: 'jitsi-meet.example.com',
18
 
19
 
19
         // XMPP MUC domain. FIXME: use XEP-0030 to discover it.
20
         // XMPP MUC domain. FIXME: use XEP-0030 to discover it.
20
-        muc: 'conference.jitsi-meet.example.com',
21
+        muc: 'conference.jitsi-meet.example.com'
21
 
22
 
22
         // When using authentication, domain for guest users.
23
         // When using authentication, domain for guest users.
23
-        //anonymousdomain: 'guest.example.com',
24
+        // anonymousdomain: 'guest.example.com',
24
 
25
 
25
         // Domain for authenticated users. Defaults to <domain>.
26
         // Domain for authenticated users. Defaults to <domain>.
26
-        //authdomain: 'jitsi-meet.example.com',
27
+        // authdomain: 'jitsi-meet.example.com',
27
 
28
 
28
         // Jirecon recording component domain.
29
         // Jirecon recording component domain.
29
-        //jirecon: 'jirecon.jitsi-meet.example.com',
30
+        // jirecon: 'jirecon.jitsi-meet.example.com',
30
 
31
 
31
         // Call control component (Jigasi).
32
         // Call control component (Jigasi).
32
-        //call_control: 'callcontrol.jitsi-meet.example.com',
33
+        // call_control: 'callcontrol.jitsi-meet.example.com',
33
 
34
 
34
         // Focus component domain. Defaults to focus.<domain>.
35
         // Focus component domain. Defaults to focus.<domain>.
35
-        //focus: 'focus.jitsi-meet.example.com',
36
+        // focus: 'focus.jitsi-meet.example.com',
36
     },
37
     },
37
 
38
 
38
     // BOSH URL. FIXME: use XEP-0156 to discover it.
39
     // BOSH URL. FIXME: use XEP-0156 to discover it.
42
     clientNode: 'http://jitsi.org/jitsimeet',
43
     clientNode: 'http://jitsi.org/jitsimeet',
43
 
44
 
44
     // The real JID of focus participant - can be overridden here
45
     // The real JID of focus participant - can be overridden here
45
-    //focusUserJid: 'focus@auth.jitsi-meet.example.com',
46
+    // focusUserJid: 'focus@auth.jitsi-meet.example.com',
46
 
47
 
47
 
48
 
48
     // Testing / experimental features.
49
     // Testing / experimental features.
51
     testing: {
52
     testing: {
52
         // Enables experimental simulcast support on Firefox.
53
         // Enables experimental simulcast support on Firefox.
53
         enableFirefoxSimulcast: false,
54
         enableFirefoxSimulcast: false,
55
+
54
         // P2P test mode disables automatic switching to P2P when there are 2
56
         // P2P test mode disables automatic switching to P2P when there are 2
55
         // participants in the conference.
57
         // participants in the conference.
56
-        p2pTestMode: false,
58
+        p2pTestMode: false
57
     },
59
     },
58
 
60
 
59
     // Disables ICE/UDP by filtering out local and remote UDP candidates in
61
     // Disables ICE/UDP by filtering out local and remote UDP candidates in
60
     // signalling.
62
     // signalling.
61
-    //webrtcIceUdpDisable: false,
63
+    // webrtcIceUdpDisable: false,
62
 
64
 
63
     // Disables ICE/TCP by filtering out local and remote TCP candidates in
65
     // Disables ICE/TCP by filtering out local and remote TCP candidates in
64
     // signalling.
66
     // signalling.
65
-    //webrtcIceTcpDisable: false,
67
+    // webrtcIceTcpDisable: false,
66
 
68
 
67
 
69
 
68
     // Media
70
     // Media
71
     // Audio
73
     // Audio
72
 
74
 
73
     // Disable measuring of audio levels.
75
     // Disable measuring of audio levels.
74
-    //disableAudioLevels: false,
76
+    // disableAudioLevels: false,
75
 
77
 
76
     // Start the conference in audio only mode (no video is being received nor
78
     // Start the conference in audio only mode (no video is being received nor
77
     // sent).
79
     // sent).
78
-    //startAudioOnly: false,
80
+    // startAudioOnly: false,
79
 
81
 
80
     // Every participant after the Nth will start audio muted.
82
     // Every participant after the Nth will start audio muted.
81
-    //startAudioMuted: 10,
83
+    // startAudioMuted: 10,
82
 
84
 
83
     // Start calls with audio muted. Unlike the option above, this one is only
85
     // Start calls with audio muted. Unlike the option above, this one is only
84
     // applied locally. FIXME: having these 2 options is confusing.
86
     // applied locally. FIXME: having these 2 options is confusing.
85
-    //startWithAudioMuted: false,
87
+    // startWithAudioMuted: false,
86
 
88
 
87
     // Video
89
     // Video
88
 
90
 
89
     // Sets the preferred resolution (height) for local video. Defaults to 720.
91
     // Sets the preferred resolution (height) for local video. Defaults to 720.
90
-    //resolution: 720,
92
+    // resolution: 720,
91
 
93
 
92
     // Enable / disable simulcast support.
94
     // Enable / disable simulcast support.
93
-    //disableSimulcast: false,
95
+    // disableSimulcast: false,
94
 
96
 
95
     // Suspend sending video if bandwidth estimation is too low. This may cause
97
     // Suspend sending video if bandwidth estimation is too low. This may cause
96
     // problems with audio playback. Disabled until these are fixed.
98
     // problems with audio playback. Disabled until these are fixed.
97
     disableSuspendVideo: true,
99
     disableSuspendVideo: true,
98
 
100
 
99
     // Every participant after the Nth will start video muted.
101
     // Every participant after the Nth will start video muted.
100
-    //startVideoMuted: 10,
102
+    // startVideoMuted: 10,
101
 
103
 
102
     // Start calls with video muted. Unlike the option above, this one is only
104
     // Start calls with video muted. Unlike the option above, this one is only
103
     // applied locally. FIXME: having these 2 options is confusing.
105
     // applied locally. FIXME: having these 2 options is confusing.
104
-    //startWithVideoMuted: false,
106
+    // startWithVideoMuted: false,
105
 
107
 
106
     // If set to true, prefer to use the H.264 video codec (if supported).
108
     // If set to true, prefer to use the H.264 video codec (if supported).
107
     // Note that it's not recommended to do this because simulcast is not
109
     // Note that it's not recommended to do this because simulcast is not
108
     // supported when  using H.264. For 1-to-1 calls this setting is enabled by
110
     // supported when  using H.264. For 1-to-1 calls this setting is enabled by
109
     // default and can be toggled in the p2p section.
111
     // default and can be toggled in the p2p section.
110
-    //preferH264: true,
112
+    // preferH264: true,
111
 
113
 
112
     // If set to true, disable H.264 video codec by stripping it out of the
114
     // If set to true, disable H.264 video codec by stripping it out of the
113
     // SDP.
115
     // SDP.
114
-    //disableH264: false,
116
+    // disableH264: false,
115
 
117
 
116
     // Desktop sharing
118
     // Desktop sharing
117
 
119
 
118
     // Enable / disable desktop sharing
120
     // Enable / disable desktop sharing
119
-    //disableDesktopSharing: false,
121
+    // disableDesktopSharing: false,
120
 
122
 
121
     // The ID of the jidesha extension for Chrome.
123
     // The ID of the jidesha extension for Chrome.
122
     desktopSharingChromeExtId: null,
124
     desktopSharingChromeExtId: null,
126
 
128
 
127
     // The media sources to use when using screen sharing with the Chrome
129
     // The media sources to use when using screen sharing with the Chrome
128
     // extension.
130
     // extension.
129
-    desktopSharingChromeSources: ['screen', 'window', 'tab'],
131
+    desktopSharingChromeSources: [ 'screen', 'window', 'tab' ],
130
 
132
 
131
     // Required version of Chrome extension
133
     // Required version of Chrome extension
132
     desktopSharingChromeMinExtVersion: '0.1',
134
     desktopSharingChromeMinExtVersion: '0.1',
149
     desktopSharingFirefoxExtensionURL: null,
151
     desktopSharingFirefoxExtensionURL: null,
150
 
152
 
151
     // Try to start calls with screen-sharing instead of camera video.
153
     // Try to start calls with screen-sharing instead of camera video.
152
-    //startScreenSharing: false,
154
+    // startScreenSharing: false,
153
 
155
 
154
     // Recording
156
     // Recording
155
 
157
 
156
     // Whether to enable recording or not.
158
     // Whether to enable recording or not.
157
-    //enableRecording: false,
159
+    // enableRecording: false,
158
 
160
 
159
     // Type for recording: one of jibri or jirecon.
161
     // Type for recording: one of jibri or jirecon.
160
-    //recordingType: 'jibri',
162
+    // recordingType: 'jibri',
161
 
163
 
162
     // Misc
164
     // Misc
163
 
165
 
165
     channelLastN: -1,
167
     channelLastN: -1,
166
 
168
 
167
     // Disables or enables RTX (RFC 4588) (defaults to false).
169
     // Disables or enables RTX (RFC 4588) (defaults to false).
168
-    //disableRtx: false,
170
+    // disableRtx: false,
169
 
171
 
170
     // Use XEP-0215 to fetch STUN and TURN servers.
172
     // Use XEP-0215 to fetch STUN and TURN servers.
171
-    //useStunTurn: true,
173
+    // useStunTurn: true,
172
 
174
 
173
     // Enable IPv6 support.
175
     // Enable IPv6 support.
174
-    //useIPv6: true,
176
+    // useIPv6: true,
175
 
177
 
176
     // Enables / disables a data communication channel with the Videobridge.
178
     // Enables / disables a data communication channel with the Videobridge.
177
     // Values can be 'datachannel', 'websocket', true (treat it as
179
     // Values can be 'datachannel', 'websocket', true (treat it as
178
     // 'datachannel'), undefined (treat it as 'datachannel') and false (don't
180
     // 'datachannel'), undefined (treat it as 'datachannel') and false (don't
179
     // open any channel).
181
     // open any channel).
180
-    //openBridgeChannel: true,
182
+    // openBridgeChannel: true,
181
 
183
 
182
 
184
 
183
     // UI
185
     // UI
184
     //
186
     //
185
 
187
 
186
     // Use display name as XMPP nickname.
188
     // Use display name as XMPP nickname.
187
-    //useNicks: false,
189
+    // useNicks: false,
188
 
190
 
189
     // Require users to always specify a display name.
191
     // Require users to always specify a display name.
190
-    //requireDisplayName: true,
192
+    // requireDisplayName: true,
191
 
193
 
192
     // Whether to use a welcome page or not. In case it's false a random room
194
     // Whether to use a welcome page or not. In case it's false a random room
193
     // will be joined when no room is specified.
195
     // will be joined when no room is specified.
195
 
197
 
196
     // Enabling the close page will ignore the welcome page redirection when
198
     // Enabling the close page will ignore the welcome page redirection when
197
     // a call is hangup.
199
     // a call is hangup.
198
-    //enableClosePage: false,
200
+    // enableClosePage: false,
199
 
201
 
200
     // Disable hiding of remote thumbnails when in a 1-on-1 conference call.
202
     // Disable hiding of remote thumbnails when in a 1-on-1 conference call.
201
-    //disable1On1Mode: false,
203
+    // disable1On1Mode: false,
204
+
202
 
205
 
206
+    // The minumum value a video's height (or width, whichever is smaller) needs
203
     // The minimum value a video's height (or width, whichever is smaller) needs
207
     // The minimum value a video's height (or width, whichever is smaller) needs
204
     // to be in order to be considered high-definition.
208
     // to be in order to be considered high-definition.
205
     minHDHeight: 540,
209
     minHDHeight: 540,
206
 
210
 
207
     // Default language for the user interface.
211
     // Default language for the user interface.
208
-    //defaultLanguage: 'en',
212
+    // defaultLanguage: 'en',
209
 
213
 
210
     // If true all users without a token will be considered guests and all users
214
     // If true all users without a token will be considered guests and all users
211
     // with token will be considered non-guests. Only guests will be allowed to
215
     // with token will be considered non-guests. Only guests will be allowed to
214
 
218
 
215
     // Message to show the users. Example: 'The service will be down for
219
     // Message to show the users. Example: 'The service will be down for
216
     // maintenance at 01:00 AM GMT,
220
     // maintenance at 01:00 AM GMT,
217
-    //noticeMessage: '',
221
+    // noticeMessage: '',
218
 
222
 
219
 
223
 
220
     // Stats
224
     // Stats
221
     //
225
     //
222
 
226
 
223
     // Whether to enable stats collection or not.
227
     // Whether to enable stats collection or not.
224
-    //disableStats: false,
228
+    // disableStats: false,
225
 
229
 
226
     // To enable sending statistics to callstats.io you must provide the
230
     // To enable sending statistics to callstats.io you must provide the
227
     // Application ID and Secret.
231
     // Application ID and Secret.
228
-    //callStatsID: '',
229
-    //callStatsSecret: '',
232
+    // callStatsID: '',
233
+    // callStatsSecret: '',
230
 
234
 
231
 
235
 
232
     // Privacy
236
     // Privacy
235
     // If third party requests are disabled, no other server will be contacted.
239
     // If third party requests are disabled, no other server will be contacted.
236
     // This means avatars will be locally generated and callstats integration
240
     // This means avatars will be locally generated and callstats integration
237
     // will not function.
241
     // will not function.
238
-    //disableThirdPartyRequests: false,
242
+    // disableThirdPartyRequests: false,
239
 
243
 
240
 
244
 
241
     // Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
245
     // Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
251
         enabled: true,
255
         enabled: true,
252
 
256
 
253
         // Use XEP-0215 to fetch STUN and TURN servers.
257
         // Use XEP-0215 to fetch STUN and TURN servers.
254
-        //useStunTurn: true,
258
+        // useStunTurn: true,
255
 
259
 
256
         // The STUN servers that will be used in the peer to peer connections
260
         // The STUN servers that will be used in the peer to peer connections
257
         stunServers: [
261
         stunServers: [
258
-            { urls: "stun:stun.l.google.com:19302" },
259
-            { urls: "stun:stun1.l.google.com:19302" },
260
-            { urls: "stun:stun2.l.google.com:19302" }
262
+            { urls: 'stun:stun.l.google.com:19302' },
263
+            { urls: 'stun:stun1.l.google.com:19302' },
264
+            { urls: 'stun:stun2.l.google.com:19302' }
261
         ],
265
         ],
262
 
266
 
263
         // If set to true, it will prefer to use H.264 for P2P calls (if H.264
267
         // If set to true, it will prefer to use H.264 for P2P calls (if H.264
266
 
270
 
267
         // If set to true, disable H.264 video codec by stripping it out of the
271
         // If set to true, disable H.264 video codec by stripping it out of the
268
         // SDP.
272
         // SDP.
269
-        //disableH264: false,
273
+        // disableH264: false,
270
 
274
 
271
         // How long we're going to wait, before going back to P2P after the 3rd
275
         // How long we're going to wait, before going back to P2P after the 3rd
272
         // participant has left the conference (to filter out page reload).
276
         // participant has left the conference (to filter out page reload).
273
-        //backToP2PDelay: 5
277
+        // backToP2PDelay: 5
274
     },
278
     },
275
 
279
 
276
 
280
 
279
     //
283
     //
280
 
284
 
281
     deploymentInfo: {
285
     deploymentInfo: {
282
-        //shard: "shard1",
283
-        //region: "europe",
284
-        //userRegion: "asia"
286
+        // shard: "shard1",
287
+        // region: "europe",
288
+        // userRegion: "asia"
285
     }
289
     }
286
 };
290
 };
291
+/* eslint-enable no-unused-vars, no-var */

+ 37
- 20
connection.js View File

13
     JitsiConnectionEvents
13
     JitsiConnectionEvents
14
 } from './react/features/base/lib-jitsi-meet';
14
 } from './react/features/base/lib-jitsi-meet';
15
 
15
 
16
-const logger = require("jitsi-meet-logger").getLogger(__filename);
16
+const logger = require('jitsi-meet-logger').getLogger(__filename);
17
 
17
 
18
 /**
18
 /**
19
  * Checks if we have data to use attach instead of connect. If we have the data
19
  * Checks if we have data to use attach instead of connect. If we have the data
27
  * @param {string} [roomName] the name of the conference.
27
  * @param {string} [roomName] the name of the conference.
28
  */
28
  */
29
 function checkForAttachParametersAndConnect(id, password, connection) {
29
 function checkForAttachParametersAndConnect(id, password, connection) {
30
-    if(window.XMPPAttachInfo){
31
-        APP.connect.status = "connecting";
30
+    if (window.XMPPAttachInfo) {
31
+        APP.connect.status = 'connecting';
32
+
32
         // When connection optimization is not deployed or enabled the default
33
         // When connection optimization is not deployed or enabled the default
33
         // value will be window.XMPPAttachInfo.status = "error"
34
         // value will be window.XMPPAttachInfo.status = "error"
34
         // If the connection optimization is deployed and enabled and there is
35
         // If the connection optimization is deployed and enabled and there is
35
         // a failure the value will be window.XMPPAttachInfo.status = "error"
36
         // a failure the value will be window.XMPPAttachInfo.status = "error"
36
-        if(window.XMPPAttachInfo.status === "error") {
37
-            connection.connect({id, password});
37
+        if (window.XMPPAttachInfo.status === 'error') {
38
+            connection.connect({ id,
39
+                password });
40
+
38
             return;
41
             return;
39
         }
42
         }
40
 
43
 
41
-        var attachOptions = window.XMPPAttachInfo.data;
42
-        if(attachOptions) {
44
+        const attachOptions = window.XMPPAttachInfo.data;
45
+
46
+        if (attachOptions) {
43
             connection.attach(attachOptions);
47
             connection.attach(attachOptions);
44
             delete window.XMPPAttachInfo.data;
48
             delete window.XMPPAttachInfo.data;
45
         } else {
49
         } else {
46
-            connection.connect({id, password});
50
+            connection.connect({ id,
51
+                password });
47
         }
52
         }
48
     } else {
53
     } else {
49
-        APP.connect.status = "ready";
54
+        APP.connect.status = 'ready';
50
         APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
55
         APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
51
             id, password, connection);
56
             id, password, connection);
52
     }
57
     }
64
     const connectionConfig = Object.assign({}, config);
69
     const connectionConfig = Object.assign({}, config);
65
     const { issuer, jwt } = APP.store.getState()['features/base/jwt'];
70
     const { issuer, jwt } = APP.store.getState()['features/base/jwt'];
66
 
71
 
67
-    connectionConfig.bosh += '?room=' + roomName;
72
+    connectionConfig.bosh += `?room=${roomName}`;
68
 
73
 
69
-    let connection
74
+    const connection
70
         = new JitsiMeetJS.JitsiConnection(
75
         = new JitsiMeetJS.JitsiConnection(
71
             null,
76
             null,
72
             jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
77
             jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
73
             connectionConfig);
78
             connectionConfig);
74
 
79
 
75
-    return new Promise(function (resolve, reject) {
80
+    return new Promise((resolve, reject) => {
76
         connection.addEventListener(
81
         connection.addEventListener(
77
             JitsiConnectionEvents.CONNECTION_ESTABLISHED,
82
             JitsiConnectionEvents.CONNECTION_ESTABLISHED,
78
             handleConnectionEstablished);
83
             handleConnectionEstablished);
83
             JitsiConnectionEvents.CONNECTION_FAILED,
88
             JitsiConnectionEvents.CONNECTION_FAILED,
84
             connectionFailedHandler);
89
             connectionFailedHandler);
85
 
90
 
91
+        /**
92
+         *
93
+         */
86
         function connectionFailedHandler(error, message, credentials) {
94
         function connectionFailedHandler(error, message, credentials) {
87
             APP.store.dispatch(
95
             APP.store.dispatch(
88
                 connectionFailed(connection, error, message, credentials));
96
                 connectionFailed(connection, error, message, credentials));
94
             }
102
             }
95
         }
103
         }
96
 
104
 
105
+        /**
106
+         *
107
+         */
97
         function unsubscribe() {
108
         function unsubscribe() {
98
             connection.removeEventListener(
109
             connection.removeEventListener(
99
                 JitsiConnectionEvents.CONNECTION_ESTABLISHED,
110
                 JitsiConnectionEvents.CONNECTION_ESTABLISHED,
103
                 handleConnectionFailed);
114
                 handleConnectionFailed);
104
         }
115
         }
105
 
116
 
117
+        /**
118
+         *
119
+         */
106
         function handleConnectionEstablished() {
120
         function handleConnectionEstablished() {
107
             APP.store.dispatch(connectionEstablished(connection));
121
             APP.store.dispatch(connectionEstablished(connection));
108
             unsubscribe();
122
             unsubscribe();
109
             resolve(connection);
123
             resolve(connection);
110
         }
124
         }
111
 
125
 
126
+        /**
127
+         *
128
+         */
112
         function handleConnectionFailed(err) {
129
         function handleConnectionFailed(err) {
113
             unsubscribe();
130
             unsubscribe();
114
-            logger.error("CONNECTION FAILED:", err);
131
+            logger.error('CONNECTION FAILED:', err);
115
             reject(err);
132
             reject(err);
116
         }
133
         }
117
 
134
 
132
  *
149
  *
133
  * @returns {Promise<JitsiConnection>}
150
  * @returns {Promise<JitsiConnection>}
134
  */
151
  */
135
-export function openConnection({id, password, retry, roomName}) {
136
-    let usernameOverride
137
-        = jitsiLocalStorage.getItem("xmpp_username_override");
138
-    let passwordOverride
139
-        = jitsiLocalStorage.getItem("xmpp_password_override");
152
+export function openConnection({ id, password, retry, roomName }) {
153
+    const usernameOverride
154
+        = jitsiLocalStorage.getItem('xmpp_username_override');
155
+    const passwordOverride
156
+        = jitsiLocalStorage.getItem('xmpp_password_override');
140
 
157
 
141
     if (usernameOverride && usernameOverride.length > 0) {
158
     if (usernameOverride && usernameOverride.length > 0) {
142
-        id = usernameOverride;
159
+        id = usernameOverride; // eslint-disable-line no-param-reassign
143
     }
160
     }
144
     if (passwordOverride && passwordOverride.length > 0) {
161
     if (passwordOverride && passwordOverride.length > 0) {
145
-        password = passwordOverride;
162
+        password = passwordOverride; // eslint-disable-line no-param-reassign
146
     }
163
     }
147
 
164
 
148
     return connect(id, password, roomName).catch(err => {
165
     return connect(id, password, roomName).catch(err => {

+ 2
- 2
index.html View File

72
                         + "font-size: medium;"
72
                         + "font-size: medium;"
73
                         + "font-weight: 400;"
73
                         + "font-weight: 400;"
74
                         + "transform: translate(-50%, -50%)'>"
74
                         + "transform: translate(-50%, -50%)'>"
75
-                        + "Uh oh! We couldn't fully download everything we needed :(" // jshint ignore:line
75
+                        + "Uh oh! We couldn't fully download everything we needed :("
76
                         + "<br/> "
76
                         + "<br/> "
77
-                        + "We will try again shortly. In the mean time, check for problems with your Internet connection!" // jshint ignore:line
77
+                        + "We will try again shortly. In the mean time, check for problems with your Internet connection!"
78
                         + "<br/><br/> "
78
                         + "<br/><br/> "
79
                         + "<div id='moreInfo' style='"
79
                         + "<div id='moreInfo' style='"
80
                         + "display: none;'>" + "Missing " + fileRef
80
                         + "display: none;'>" + "Missing " + fileRef

+ 32
- 20
interface_config.js View File

1
-var interfaceConfig = { // eslint-disable-line no-unused-vars
1
+/* eslint-disable no-unused-vars, no-var, max-len */
2
+var interfaceConfig = {
2
     // TO FIX: this needs to be handled from SASS variables. There are some
3
     // TO FIX: this needs to be handled from SASS variables. There are some
3
     // methods allowing to use variables both in css and js.
4
     // methods allowing to use variables both in css and js.
4
     DEFAULT_BACKGROUND: '#474747',
5
     DEFAULT_BACKGROUND: '#474747',
6
+
5
     /**
7
     /**
6
      * In case the desktop sharing is disabled through the config the button
8
      * In case the desktop sharing is disabled through the config the button
7
      * will not be hidden, but displayed as disabled with this text us as
9
      * will not be hidden, but displayed as disabled with this text us as
10
     DESKTOP_SHARING_BUTTON_DISABLED_TOOLTIP: null,
12
     DESKTOP_SHARING_BUTTON_DISABLED_TOOLTIP: null,
11
     INITIAL_TOOLBAR_TIMEOUT: 20000,
13
     INITIAL_TOOLBAR_TIMEOUT: 20000,
12
     TOOLBAR_TIMEOUT: 4000,
14
     TOOLBAR_TIMEOUT: 4000,
13
-    DEFAULT_REMOTE_DISPLAY_NAME: "Fellow Jitster",
14
-    DEFAULT_LOCAL_DISPLAY_NAME: "me",
15
+    DEFAULT_REMOTE_DISPLAY_NAME: 'Fellow Jitster',
16
+    DEFAULT_LOCAL_DISPLAY_NAME: 'me',
15
     SHOW_JITSI_WATERMARK: true,
17
     SHOW_JITSI_WATERMARK: true,
16
-    JITSI_WATERMARK_LINK: "https://jitsi.org",
18
+    JITSI_WATERMARK_LINK: 'https://jitsi.org',
19
+
17
     // if watermark is disabled by default, it can be shown only for guests
20
     // if watermark is disabled by default, it can be shown only for guests
18
     SHOW_WATERMARK_FOR_GUESTS: true,
21
     SHOW_WATERMARK_FOR_GUESTS: true,
19
     SHOW_BRAND_WATERMARK: false,
22
     SHOW_BRAND_WATERMARK: false,
20
-    BRAND_WATERMARK_LINK: "",
23
+    BRAND_WATERMARK_LINK: '',
21
     SHOW_POWERED_BY: false,
24
     SHOW_POWERED_BY: false,
22
     GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
25
     GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
23
-    APP_NAME: "Jitsi Meet",
24
-    LANG_DETECTION: false,    // Allow i18n to detect the system language
26
+    APP_NAME: 'Jitsi Meet',
27
+    LANG_DETECTION: false, // Allow i18n to detect the system language
25
     INVITATION_POWERED_BY: true,
28
     INVITATION_POWERED_BY: true,
29
+
26
     /**
30
     /**
27
      * If we should show authentication block in profile
31
      * If we should show authentication block in profile
28
      */
32
      */
29
     AUTHENTICATION_ENABLE: true,
33
     AUTHENTICATION_ENABLE: true,
34
+
30
     /**
35
     /**
31
      * the toolbar buttons line is intentionally left in one line, to be able
36
      * the toolbar buttons line is intentionally left in one line, to be able
32
      * to easily override values or remove them using regex
37
      * to easily override values or remove them using regex
33
      */
38
      */
34
     TOOLBAR_BUTTONS: [
39
     TOOLBAR_BUTTONS: [
35
-        //main toolbar
36
-        'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup', // jshint ignore:line
37
-        //extended toolbar
38
-        'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip'], // jshint ignore:line
40
+
41
+        // main toolbar
42
+        'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup',
43
+
44
+        // extended toolbar
45
+        'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip' ],
46
+
39
     /**
47
     /**
40
      * Main Toolbar Buttons
48
      * Main Toolbar Buttons
41
      * All of them should be in TOOLBAR_BUTTONS
49
      * All of them should be in TOOLBAR_BUTTONS
42
      */
50
      */
43
-    MAIN_TOOLBAR_BUTTONS: ['microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup'], // jshint ignore:line
44
-    SETTINGS_SECTIONS: ['language', 'devices', 'moderator'],
45
-    INVITE_OPTIONS: ['invite', 'dialout', 'addtocall'],
51
+    MAIN_TOOLBAR_BUTTONS: [ 'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup' ],
52
+    SETTINGS_SECTIONS: [ 'language', 'devices', 'moderator' ],
53
+    INVITE_OPTIONS: [ 'invite', 'dialout', 'addtocall' ],
54
+
46
     // Determines how the video would fit the screen. 'both' would fit the whole
55
     // Determines how the video would fit the screen. 'both' would fit the whole
47
     // screen, 'height' would fit the original video height to the height of the
56
     // screen, 'height' would fit the original video height to the height of the
48
     // screen, 'width' would fit the original video width to the width of the
57
     // screen, 'width' would fit the original video width to the width of the
49
     // screen respecting ratio.
58
     // screen respecting ratio.
50
     VIDEO_LAYOUT_FIT: 'both',
59
     VIDEO_LAYOUT_FIT: 'both',
51
     SHOW_CONTACTLIST_AVATARS: true,
60
     SHOW_CONTACTLIST_AVATARS: true,
61
+
52
     /**
62
     /**
53
      * Whether to only show the filmstrip (and hide the toolbar).
63
      * Whether to only show the filmstrip (and hide the toolbar).
54
      */
64
      */
59
      */
69
      */
60
     VERTICAL_FILMSTRIP: true,
70
     VERTICAL_FILMSTRIP: true,
61
 
71
 
62
-    //A html text to be shown to guests on the close page, false disables it
72
+    // A html text to be shown to guests on the close page, false disables it
63
     CLOSE_PAGE_GUEST_HINT: false,
73
     CLOSE_PAGE_GUEST_HINT: false,
64
     RANDOM_AVATAR_URL_PREFIX: false,
74
     RANDOM_AVATAR_URL_PREFIX: false,
65
     RANDOM_AVATAR_URL_SUFFIX: false,
75
     RANDOM_AVATAR_URL_SUFFIX: false,
66
     FILM_STRIP_MAX_HEIGHT: 120,
76
     FILM_STRIP_MAX_HEIGHT: 120,
77
+
67
     // Enables feedback star animation.
78
     // Enables feedback star animation.
68
     ENABLE_FEEDBACK_ANIMATION: false,
79
     ENABLE_FEEDBACK_ANIMATION: false,
69
     DISABLE_FOCUS_INDICATOR: false,
80
     DISABLE_FOCUS_INDICATOR: false,
76
      * @type {boolean}
87
      * @type {boolean}
77
      */
88
      */
78
     DISABLE_RINGING: false,
89
     DISABLE_RINGING: false,
79
-    AUDIO_LEVEL_PRIMARY_COLOR: "rgba(255,255,255,0.4)",
80
-    AUDIO_LEVEL_SECONDARY_COLOR: "rgba(255,255,255,0.2)",
90
+    AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
91
+    AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)',
81
     POLICY_LOGO: null,
92
     POLICY_LOGO: null,
82
-    LOCAL_THUMBNAIL_RATIO: 16/9, //16:9
83
-    REMOTE_THUMBNAIL_RATIO: 1, //1:1
93
+    LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
94
+    REMOTE_THUMBNAIL_RATIO: 1, // 1:1
84
     // Documentation reference for the live streaming feature.
95
     // Documentation reference for the live streaming feature.
85
-    LIVE_STREAMING_HELP_LINK: "https://jitsi.org/live",
96
+    LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live',
86
 
97
 
87
     /**
98
     /**
88
      * Whether the mobile app Jitsi Meet is to be promoted to participants
99
      * Whether the mobile app Jitsi Meet is to be promoted to participants
131
      */
142
      */
132
     // ADD_PEOPLE_APP_NAME: ""
143
     // ADD_PEOPLE_APP_NAME: ""
133
 };
144
 };
145
+/* eslint-enable no-unused-vars, no-var, max-len */

+ 9
- 4
logging_config.js View File

1
+/* eslint-disable no-unused-vars, no-var */
1
 // Logging configuration
2
 // Logging configuration
2
-var loggingConfig = { // eslint-disable-line no-unused-vars
3
-    //default log level for the app and lib-jitsi-meet
3
+var loggingConfig = {
4
+    // default log level for the app and lib-jitsi-meet
4
     defaultLogLevel: 'trace',
5
     defaultLogLevel: 'trace',
6
+
5
     // Option to disable LogCollector (which stores the logs on CallStats)
7
     // Option to disable LogCollector (which stores the logs on CallStats)
6
-    //disableLogCollector: true,
8
+    // disableLogCollector: true,
9
+
7
     // Logging level adjustments for verbose modules:
10
     // Logging level adjustments for verbose modules:
8
     'modules/xmpp/strophe.util.js': 'log',
11
     'modules/xmpp/strophe.util.js': 'log',
9
     'modules/statistics/CallStats.js': 'info'
12
     'modules/statistics/CallStats.js': 'info'
10
-};
13
+};
14
+
15
+/* eslint-enable no-unused-vars, no-var */

+ 109
- 62
modules/FollowMe.js View File

13
  * See the License for the specific language governing permissions and
13
  * See the License for the specific language governing permissions and
14
  * limitations under the License.
14
  * limitations under the License.
15
  */
15
  */
16
-const logger = require("jitsi-meet-logger").getLogger(__filename);
16
+const logger = require('jitsi-meet-logger').getLogger(__filename);
17
 
17
 
18
 import UIEvents from '../service/UI/UIEvents';
18
 import UIEvents from '../service/UI/UIEvents';
19
 import VideoLayout from './UI/videolayout/VideoLayout';
19
 import VideoLayout from './UI/videolayout/VideoLayout';
23
  * {State} for the local state at the time of this writing) of a {FollowMe}
23
  * {State} for the local state at the time of this writing) of a {FollowMe}
24
  * (instance) between participants.
24
  * (instance) between participants.
25
  */
25
  */
26
-const _COMMAND = "follow-me";
26
+const _COMMAND = 'follow-me';
27
 
27
 
28
 /**
28
 /**
29
  * The timeout after which a follow-me command that has been received will be
29
  * The timeout after which a follow-me command that has been received will be
50
      * the property, the old value of the property before the change, and the
50
      * the property, the old value of the property before the change, and the
51
      * new value of the property after the change.
51
      * new value of the property after the change.
52
      */
52
      */
53
-    constructor (propertyChangeCallback) {
53
+    constructor(propertyChangeCallback) {
54
         this._propertyChangeCallback = propertyChangeCallback;
54
         this._propertyChangeCallback = propertyChangeCallback;
55
     }
55
     }
56
 
56
 
57
-    get filmstripVisible () { return this._filmstripVisible; }
57
+    /**
58
+     *
59
+     */
60
+    get filmstripVisible() {
61
+        return this._filmstripVisible;
62
+    }
63
+
64
+    /**
65
+     *
66
+     */
67
+    set filmstripVisible(b) {
68
+        const oldValue = this._filmstripVisible;
58
 
69
 
59
-    set filmstripVisible (b) {
60
-        var oldValue = this._filmstripVisible;
61
         if (oldValue !== b) {
70
         if (oldValue !== b) {
62
             this._filmstripVisible = b;
71
             this._filmstripVisible = b;
63
             this._firePropertyChange('filmstripVisible', oldValue, b);
72
             this._firePropertyChange('filmstripVisible', oldValue, b);
64
         }
73
         }
65
     }
74
     }
66
 
75
 
67
-    get nextOnStage() { return this._nextOnStage; }
76
+    /**
77
+     *
78
+     */
79
+    get nextOnStage() {
80
+        return this._nextOnStage;
81
+    }
68
 
82
 
83
+    /**
84
+     *
85
+     */
69
     set nextOnStage(id) {
86
     set nextOnStage(id) {
70
-        var oldValue = this._nextOnStage;
87
+        const oldValue = this._nextOnStage;
88
+
71
         if (oldValue !== id) {
89
         if (oldValue !== id) {
72
             this._nextOnStage = id;
90
             this._nextOnStage = id;
73
             this._firePropertyChange('nextOnStage', oldValue, id);
91
             this._firePropertyChange('nextOnStage', oldValue, id);
74
         }
92
         }
75
     }
93
     }
76
 
94
 
77
-    get sharedDocumentVisible () { return this._sharedDocumentVisible; }
95
+    /**
96
+     *
97
+     */
98
+    get sharedDocumentVisible() {
99
+        return this._sharedDocumentVisible;
100
+    }
101
+
102
+    /**
103
+     *
104
+     */
105
+    set sharedDocumentVisible(b) {
106
+        const oldValue = this._sharedDocumentVisible;
78
 
107
 
79
-    set sharedDocumentVisible (b) {
80
-        var oldValue = this._sharedDocumentVisible;
81
         if (oldValue !== b) {
108
         if (oldValue !== b) {
82
             this._sharedDocumentVisible = b;
109
             this._sharedDocumentVisible = b;
83
             this._firePropertyChange('sharedDocumentVisible', oldValue, b);
110
             this._firePropertyChange('sharedDocumentVisible', oldValue, b);
93
      * @param oldValue the value of {property} before the change
120
      * @param oldValue the value of {property} before the change
94
      * @param newValue the value of {property} after the change
121
      * @param newValue the value of {property} after the change
95
      */
122
      */
96
-    _firePropertyChange (property, oldValue, newValue) {
97
-        var propertyChangeCallback = this._propertyChangeCallback;
98
-        if (propertyChangeCallback)
123
+    _firePropertyChange(property, oldValue, newValue) {
124
+        const propertyChangeCallback = this._propertyChangeCallback;
125
+
126
+        if (propertyChangeCallback) {
99
             propertyChangeCallback(property, oldValue, newValue);
127
             propertyChangeCallback(property, oldValue, newValue);
128
+        }
100
     }
129
     }
101
 }
130
 }
102
 
131
 
118
      * destination (model/state) to receive from the remote moderator if the
147
      * destination (model/state) to receive from the remote moderator if the
119
      * local participant is not the moderator
148
      * local participant is not the moderator
120
      */
149
      */
121
-    constructor (conference, UI) {
150
+    constructor(conference, UI) {
122
         this._conference = conference;
151
         this._conference = conference;
123
         this._UI = UI;
152
         this._UI = UI;
124
         this.nextOnStageTimer = 0;
153
         this.nextOnStageTimer = 0;
150
         this._nextOnStage(pinnedId, Boolean(pinnedId));
179
         this._nextOnStage(pinnedId, Boolean(pinnedId));
151
 
180
 
152
         // check whether shared document is enabled/initialized
181
         // check whether shared document is enabled/initialized
153
-        if(this._UI.getSharedDocumentManager())
182
+        if (this._UI.getSharedDocumentManager()) {
154
             this._sharedDocumentToggled
183
             this._sharedDocumentToggled
155
                 .bind(this, this._UI.getSharedDocumentManager().isVisible());
184
                 .bind(this, this._UI.getSharedDocumentManager().isVisible());
185
+        }
156
     }
186
     }
157
 
187
 
158
     /**
188
     /**
162
      * the states of interest.
192
      * the states of interest.
163
      * @private
193
      * @private
164
      */
194
      */
165
-    _addFollowMeListeners () {
195
+    _addFollowMeListeners() {
166
         this.filmstripEventHandler = this._filmstripToggled.bind(this);
196
         this.filmstripEventHandler = this._filmstripToggled.bind(this);
167
         this._UI.addListener(UIEvents.TOGGLED_FILMSTRIP,
197
         this._UI.addListener(UIEvents.TOGGLED_FILMSTRIP,
168
                             this.filmstripEventHandler);
198
                             this.filmstripEventHandler);
169
 
199
 
170
-        var self = this;
171
-        this.pinnedEndpointEventHandler = function (videoId, isPinned) {
200
+        const self = this;
201
+
202
+        this.pinnedEndpointEventHandler = function(videoId, isPinned) {
172
             self._nextOnStage(videoId, isPinned);
203
             self._nextOnStage(videoId, isPinned);
173
         };
204
         };
174
         this._UI.addListener(UIEvents.PINNED_ENDPOINT,
205
         this._UI.addListener(UIEvents.PINNED_ENDPOINT,
175
                             this.pinnedEndpointEventHandler);
206
                             this.pinnedEndpointEventHandler);
176
 
207
 
177
         this.sharedDocEventHandler = this._sharedDocumentToggled.bind(this);
208
         this.sharedDocEventHandler = this._sharedDocumentToggled.bind(this);
178
-        this._UI.addListener( UIEvents.TOGGLED_SHARED_DOCUMENT,
209
+        this._UI.addListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
179
                             this.sharedDocEventHandler);
210
                             this.sharedDocEventHandler);
180
     }
211
     }
181
 
212
 
183
      * Removes all follow me listeners.
214
      * Removes all follow me listeners.
184
      * @private
215
      * @private
185
      */
216
      */
186
-    _removeFollowMeListeners () {
217
+    _removeFollowMeListeners() {
187
         this._UI.removeListener(UIEvents.TOGGLED_FILMSTRIP,
218
         this._UI.removeListener(UIEvents.TOGGLED_FILMSTRIP,
188
                                 this.filmstripEventHandler);
219
                                 this.filmstripEventHandler);
189
         this._UI.removeListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
220
         this._UI.removeListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
198
      * @param enable {true} to enable the follow me functionality, {false} -
229
      * @param enable {true} to enable the follow me functionality, {false} -
199
      * to disable it
230
      * to disable it
200
      */
231
      */
201
-    enableFollowMe (enable) {
232
+    enableFollowMe(enable) {
202
         if (enable) {
233
         if (enable) {
203
             this._setFollowMeInitialState();
234
             this._setFollowMeInitialState();
204
             this._addFollowMeListeners();
235
             this._addFollowMeListeners();
205
-        }
206
-        else
236
+        } else {
207
             this._removeFollowMeListeners();
237
             this._removeFollowMeListeners();
238
+        }
208
     }
239
     }
209
 
240
 
210
     /**
241
     /**
214
      * @param filmstripVisible {Boolean} {true} if the filmstrip was shown (as a
245
      * @param filmstripVisible {Boolean} {true} if the filmstrip was shown (as a
215
      * result of the toggle) or {false} if the filmstrip was hidden
246
      * result of the toggle) or {false} if the filmstrip was hidden
216
      */
247
      */
217
-    _filmstripToggled (filmstripVisible) {
248
+    _filmstripToggled(filmstripVisible) {
218
         this._local.filmstripVisible = filmstripVisible;
249
         this._local.filmstripVisible = filmstripVisible;
219
     }
250
     }
220
 
251
 
225
      * @param sharedDocumentVisible {Boolean} {true} if the shared document was
256
      * @param sharedDocumentVisible {Boolean} {true} if the shared document was
226
      * shown (as a result of the toggle) or {false} if it was hidden
257
      * shown (as a result of the toggle) or {false} if it was hidden
227
      */
258
      */
228
-    _sharedDocumentToggled (sharedDocumentVisible) {
259
+    _sharedDocumentToggled(sharedDocumentVisible) {
229
         this._local.sharedDocumentVisible = sharedDocumentVisible;
260
         this._local.sharedDocumentVisible = sharedDocumentVisible;
230
     }
261
     }
231
 
262
 
237
      * unpinned
268
      * unpinned
238
      * @private
269
      * @private
239
      */
270
      */
240
-    _nextOnStage (videoId, isPinned) {
241
-        if (!this._conference.isModerator)
271
+    _nextOnStage(videoId, isPinned) {
272
+        if (!this._conference.isModerator) {
242
             return;
273
             return;
274
+        }
275
+
276
+        let nextOnStage = null;
243
 
277
 
244
-        var nextOnStage = null;
245
-        if(isPinned)
278
+        if (isPinned) {
246
             nextOnStage = videoId;
279
             nextOnStage = videoId;
280
+        }
247
 
281
 
248
         this._local.nextOnStage = nextOnStage;
282
         this._local.nextOnStage = nextOnStage;
249
     }
283
     }
251
     /**
285
     /**
252
      * Sends the follow-me command, when a local property change occurs.
286
      * Sends the follow-me command, when a local property change occurs.
253
      *
287
      *
254
-     * @param property the property name
255
-     * @param oldValue the old value
256
-     * @param newValue the new value
257
      * @private
288
      * @private
258
      */
289
      */
259
-    // eslint-disable-next-line no-unused-vars
260
-    _localPropertyChange (property, oldValue, newValue) {
290
+    _localPropertyChange() { // eslint-disable-next-line no-unused-vars
261
         // Only a moderator is allowed to send commands.
291
         // Only a moderator is allowed to send commands.
262
         const conference = this._conference;
292
         const conference = this._conference;
263
-        if (!conference.isModerator)
293
+
294
+        if (!conference.isModerator) {
264
             return;
295
             return;
296
+        }
265
 
297
 
266
         const commands = conference.commands;
298
         const commands = conference.commands;
299
+
267
         // XXX The "Follow Me" command represents a snapshot of all states
300
         // XXX The "Follow Me" command represents a snapshot of all states
268
         // which are to be followed so don't forget to removeCommand before
301
         // which are to be followed so don't forget to removeCommand before
269
         // sendCommand!
302
         // sendCommand!
303
+
270
         commands.removeCommand(_COMMAND);
304
         commands.removeCommand(_COMMAND);
271
         const local = this._local;
305
         const local = this._local;
306
+
272
         commands.sendCommandOnce(
307
         commands.sendCommandOnce(
273
                 _COMMAND,
308
                 _COMMAND,
274
                 {
309
                 {
289
      * notable idiosyncrasy of the Command(s) API to be mindful of here is that
324
      * notable idiosyncrasy of the Command(s) API to be mindful of here is that
290
      * the command may be issued by the local participant.
325
      * the command may be issued by the local participant.
291
      */
326
      */
292
-    _onFollowMeCommand ({ attributes }, id) {
327
+    _onFollowMeCommand({ attributes }, id) {
293
         // We require to know who issued the command because (1) only a
328
         // We require to know who issued the command because (1) only a
294
         // moderator is allowed to send commands and (2) a command MUST be
329
         // moderator is allowed to send commands and (2) a command MUST be
295
         // issued by a defined commander.
330
         // issued by a defined commander.
296
-        if (typeof id === 'undefined')
331
+        if (typeof id === 'undefined') {
297
             return;
332
             return;
333
+        }
298
 
334
 
299
         // The Command(s) API will send us our own commands and we don't want
335
         // The Command(s) API will send us our own commands and we don't want
300
         // to act upon them.
336
         // to act upon them.
301
-        if (this._conference.isLocalId(id))
337
+        if (this._conference.isLocalId(id)) {
302
             return;
338
             return;
339
+        }
340
+
341
+        if (!this._conference.isParticipantModerator(id)) {
342
+            logger.warn('Received follow-me command '
343
+                + 'not from moderator');
303
 
344
 
304
-        if (!this._conference.isParticipantModerator(id))
305
-        {
306
-            logger.warn('Received follow-me command ' +
307
-                'not from moderator');
308
             return;
345
             return;
309
         }
346
         }
310
 
347
 
328
             // attributes, at least) at the time of this writing so take into
365
             // attributes, at least) at the time of this writing so take into
329
             // account that what originated as a Boolean may be a String on
366
             // account that what originated as a Boolean may be a String on
330
             // receipt.
367
             // receipt.
331
-            filmstripVisible = (filmstripVisible == 'true');
368
+            // eslint-disable-next-line eqeqeq, no-param-reassign
369
+            filmstripVisible = filmstripVisible == 'true';
332
 
370
 
333
             // FIXME The UI (module) very likely doesn't (want to) expose its
371
             // FIXME The UI (module) very likely doesn't (want to) expose its
334
             // eventEmitter as a public field. I'm not sure at the time of this
372
             // eventEmitter as a public field. I'm not sure at the time of this
335
             // writing whether calling UI.toggleFilmstrip() is acceptable (from
373
             // writing whether calling UI.toggleFilmstrip() is acceptable (from
336
             // a design standpoint) either.
374
             // a design standpoint) either.
337
-            if (filmstripVisible !== this._UI.isFilmstripVisible())
375
+            if (filmstripVisible !== this._UI.isFilmstripVisible()) {
338
                 this._UI.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
376
                 this._UI.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
377
+            }
339
         }
378
         }
340
     }
379
     }
341
 
380
 
347
      * @private
386
      * @private
348
      */
387
      */
349
     _onNextOnStage(id) {
388
     _onNextOnStage(id) {
350
-        var clickId = null;
351
-        var pin;
389
+        let clickId = null;
390
+        let pin;
391
+
352
         // if there is an id which is not pinned we schedule it for pin only the
392
         // if there is an id which is not pinned we schedule it for pin only the
353
         // first time
393
         // first time
354
-        if(typeof id !== 'undefined' && !VideoLayout.isPinned(id)) {
394
+
395
+        if (typeof id !== 'undefined' && !VideoLayout.isPinned(id)) {
355
             clickId = id;
396
             clickId = id;
356
             pin = true;
397
             pin = true;
357
-        }
358
-        // if there is no id, but we have a pinned one, let's unpin
359
-        else if (typeof id == 'undefined' && VideoLayout.getPinnedId()) {
398
+        } else if (typeof id === 'undefined' && VideoLayout.getPinnedId()) {
399
+            // if there is no id, but we have a pinned one, let's unpin
360
             clickId = VideoLayout.getPinnedId();
400
             clickId = VideoLayout.getPinnedId();
361
             pin = false;
401
             pin = false;
362
         }
402
         }
363
 
403
 
364
-        if (clickId)
404
+        if (clickId) {
365
             this._pinVideoThumbnailById(clickId, pin);
405
             this._pinVideoThumbnailById(clickId, pin);
406
+        }
366
     }
407
     }
367
 
408
 
368
     /**
409
     /**
378
             // attributes, at least) at the time of this writing so take into
419
             // attributes, at least) at the time of this writing so take into
379
             // account that what originated as a Boolean may be a String on
420
             // account that what originated as a Boolean may be a String on
380
             // receipt.
421
             // receipt.
381
-            sharedDocumentVisible = (sharedDocumentVisible == 'true');
422
+            // eslint-disable-next-line eqeqeq, no-param-reassign
423
+            sharedDocumentVisible = sharedDocumentVisible == 'true';
382
 
424
 
383
             if (sharedDocumentVisible
425
             if (sharedDocumentVisible
384
-                !== this._UI.getSharedDocumentManager().isVisible())
426
+                !== this._UI.getSharedDocumentManager().isVisible()) {
385
                 this._UI.getSharedDocumentManager().toggleEtherpad();
427
                 this._UI.getSharedDocumentManager().toggleEtherpad();
428
+            }
386
         }
429
         }
387
     }
430
     }
388
 
431
 
394
      * @private
437
      * @private
395
      */
438
      */
396
     _pinVideoThumbnailById(clickId, pin) {
439
     _pinVideoThumbnailById(clickId, pin) {
397
-        var self = this;
398
-        var smallVideo = VideoLayout.getSmallVideo(clickId);
440
+        const self = this;
441
+        const smallVideo = VideoLayout.getSmallVideo(clickId);
399
 
442
 
400
         // If the SmallVideo for the given clickId exists we proceed with the
443
         // If the SmallVideo for the given clickId exists we proceed with the
401
         // pin/unpin.
444
         // pin/unpin.
402
         if (smallVideo) {
445
         if (smallVideo) {
403
             this.nextOnStageTimer = 0;
446
             this.nextOnStageTimer = 0;
404
             clearTimeout(this.nextOnStageTimout);
447
             clearTimeout(this.nextOnStageTimout);
448
+            /* eslint-disable no-mixed-operators */
405
             if (pin && !VideoLayout.isPinned(clickId)
449
             if (pin && !VideoLayout.isPinned(clickId)
406
-                || !pin && VideoLayout.isPinned(clickId))
450
+                || !pin && VideoLayout.isPinned(clickId)) {
451
+                /* eslint-disable no-mixed-operators */
407
                 VideoLayout.handleVideoThumbClicked(clickId);
452
                 VideoLayout.handleVideoThumbClicked(clickId);
408
-        }
409
-        // If there's no SmallVideo object for the given id, lets wait and see
410
-        // if it's going to be created in the next 30sec.
411
-        else {
412
-            this.nextOnStageTimout = setTimeout(function () {
453
+            }
454
+        } else {
455
+            // If there's no SmallVideo object for the given id, lets wait and
456
+            // see if it's going to be created in the next 30sec.
457
+            this.nextOnStageTimout = setTimeout(function() {
413
                 if (self.nextOnStageTimer > _FOLLOW_ME_RECEIVED_TIMEOUT) {
458
                 if (self.nextOnStageTimer > _FOLLOW_ME_RECEIVED_TIMEOUT) {
414
                     self.nextOnStageTimer = 0;
459
                     self.nextOnStageTimer = 0;
460
+
415
                     return;
461
                     return;
416
                 }
462
                 }
417
 
463
 
464
+                // eslint-disable-next-line no-invalid-this
418
                 this.nextOnStageTimer++;
465
                 this.nextOnStageTimer++;
419
                 self._pinVideoThumbnailById(clickId, pin);
466
                 self._pinVideoThumbnailById(clickId, pin);
420
             }, 1000);
467
             }, 1000);

+ 228
- 203
modules/UI/UI.js
File diff suppressed because it is too large
View File


+ 1
- 1
modules/UI/UIErrors.js View File

7
  *
7
  *
8
  * @type {{FEEDBACK_REQUEST_IN_PROGRESS: string}}
8
  * @type {{FEEDBACK_REQUEST_IN_PROGRESS: string}}
9
  */
9
  */
10
-export const FEEDBACK_REQUEST_IN_PROGRESS = "FeedbackRequestInProgress";
10
+export const FEEDBACK_REQUEST_IN_PROGRESS = 'FeedbackRequestInProgress';

+ 23
- 19
modules/UI/audio_levels/AudioLevels.js View File

1
 /* global interfaceConfig */
1
 /* global interfaceConfig */
2
 
2
 
3
-import UIUtil from "../util/UIUtil";
3
+import UIUtil from '../util/UIUtil';
4
 
4
 
5
 /**
5
 /**
6
  * Responsible for drawing audio levels.
6
  * Responsible for drawing audio levels.
19
     _setDotLevel(elementID, index, opacity) {
19
     _setDotLevel(elementID, index, opacity) {
20
         let audioSpan
20
         let audioSpan
21
             = document.getElementById(elementID)
21
             = document.getElementById(elementID)
22
-                .getElementsByClassName("audioindicator");
22
+                .getElementsByClassName('audioindicator');
23
 
23
 
24
         // Make sure the audio span is still around.
24
         // Make sure the audio span is still around.
25
-        if (audioSpan && audioSpan.length > 0)
25
+        if (audioSpan && audioSpan.length > 0) {
26
             audioSpan = audioSpan[0];
26
             audioSpan = audioSpan[0];
27
-        else
27
+        } else {
28
             return;
28
             return;
29
+        }
29
 
30
 
30
-        let audioTopDots
31
-            = audioSpan.getElementsByClassName("audiodot-top");
32
-        let audioDotMiddle
33
-            = audioSpan.getElementsByClassName("audiodot-middle");
34
-        let audioBottomDots
35
-            = audioSpan.getElementsByClassName("audiodot-bottom");
31
+        const audioTopDots
32
+            = audioSpan.getElementsByClassName('audiodot-top');
33
+        const audioDotMiddle
34
+            = audioSpan.getElementsByClassName('audiodot-middle');
35
+        const audioBottomDots
36
+            = audioSpan.getElementsByClassName('audiodot-bottom');
36
 
37
 
37
         // First take care of the middle dot case.
38
         // First take care of the middle dot case.
38
-        if (index === 0){
39
+        if (index === 0) {
39
             audioDotMiddle[0].style.opacity = opacity;
40
             audioDotMiddle[0].style.opacity = opacity;
41
+
40
             return;
42
             return;
41
         }
43
         }
42
 
44
 
43
         // Index > 0 : we are setting non-middle dots.
45
         // Index > 0 : we are setting non-middle dots.
44
-        index--;
46
+        index--;// eslint-disable-line no-param-reassign
45
         audioBottomDots[index].style.opacity = opacity;
47
         audioBottomDots[index].style.opacity = opacity;
46
         audioTopDots[this.sideDotsCount - index - 1].style.opacity = opacity;
48
         audioTopDots[this.sideDotsCount - index - 1].style.opacity = opacity;
47
     },
49
     },
52
      * @param audioLevel the new audio level to set.
54
      * @param audioLevel the new audio level to set.
53
      */
55
      */
54
     updateLargeVideoAudioLevel(elementId, audioLevel) {
56
     updateLargeVideoAudioLevel(elementId, audioLevel) {
55
-        let element = document.getElementById(elementId);
57
+        const element = document.getElementById(elementId);
56
 
58
 
57
-        if(!UIUtil.isVisible(element))
59
+        if (!UIUtil.isVisible(element)) {
58
             return;
60
             return;
61
+        }
59
 
62
 
60
         let level = parseFloat(audioLevel);
63
         let level = parseFloat(audioLevel);
61
 
64
 
62
         level = isNaN(level) ? 0 : level;
65
         level = isNaN(level) ? 0 : level;
63
 
66
 
64
-        let shadowElement = element.getElementsByClassName("dynamic-shadow");
67
+        let shadowElement = element.getElementsByClassName('dynamic-shadow');
65
 
68
 
66
-        if (shadowElement && shadowElement.length > 0)
69
+        if (shadowElement && shadowElement.length > 0) {
67
             shadowElement = shadowElement[0];
70
             shadowElement = shadowElement[0];
71
+        }
68
 
72
 
69
         shadowElement.style.boxShadow = this._updateLargeVideoShadow(level);
73
         shadowElement.style.boxShadow = this._updateLargeVideoShadow(level);
70
     },
74
     },
83
 
87
 
84
         // External circle audio level.
88
         // External circle audio level.
85
         const ext = {
89
         const ext = {
86
-            level: (int.level * scale * level + int.level).toFixed(0),
90
+            level: ((int.level * scale * level) + int.level).toFixed(0),
87
             color: interfaceConfig.AUDIO_LEVEL_SECONDARY_COLOR
91
             color: interfaceConfig.AUDIO_LEVEL_SECONDARY_COLOR
88
         };
92
         };
89
 
93
 
94
         ext.blur = ext.level ? 6 : 0;
98
         ext.blur = ext.level ? 6 : 0;
95
 
99
 
96
         return [
100
         return [
97
-            `0 0 ${ int.blur }px ${ int.level }px ${ int.color }`,
98
-            `0 0 ${ ext.blur }px ${ ext.level }px ${ ext.color }`
101
+            `0 0 ${int.blur}px ${int.level}px ${int.color}`,
102
+            `0 0 ${ext.blur}px ${ext.level}px ${ext.color}`
99
         ].join(', ');
103
         ].join(', ');
100
     }
104
     }
101
 };
105
 };

+ 87
- 66
modules/UI/authentication/AuthHandler.js View File

9
 
9
 
10
 import LoginDialog from './LoginDialog';
10
 import LoginDialog from './LoginDialog';
11
 
11
 
12
-const logger = require("jitsi-meet-logger").getLogger(__filename);
12
+const logger = require('jitsi-meet-logger').getLogger(__filename);
13
 
13
 
14
 let externalAuthWindow;
14
 let externalAuthWindow;
15
 let authRequiredDialog;
15
 let authRequiredDialog;
16
 
16
 
17
-let isTokenAuthEnabled
18
-    = typeof config.tokenAuthUrl === "string" && config.tokenAuthUrl.length;
19
-let getTokenAuthUrl
17
+const isTokenAuthEnabled
18
+    = typeof config.tokenAuthUrl === 'string' && config.tokenAuthUrl.length;
19
+const getTokenAuthUrl
20
     = JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
20
     = JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
21
 
21
 
22
 /**
22
 /**
26
  * @param {JitsiConference} room
26
  * @param {JitsiConference} room
27
  * @param {string} [lockPassword] password to use if the conference is locked
27
  * @param {string} [lockPassword] password to use if the conference is locked
28
  */
28
  */
29
-function doExternalAuth (room, lockPassword) {
29
+function doExternalAuth(room, lockPassword) {
30
     if (externalAuthWindow) {
30
     if (externalAuthWindow) {
31
         externalAuthWindow.focus();
31
         externalAuthWindow.focus();
32
+
32
         return;
33
         return;
33
     }
34
     }
34
     if (room.isJoined()) {
35
     if (room.isJoined()) {
35
         let getUrl;
36
         let getUrl;
37
+
36
         if (isTokenAuthEnabled) {
38
         if (isTokenAuthEnabled) {
37
             getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
39
             getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
38
             initJWTTokenListener(room);
40
             initJWTTokenListener(room);
39
         } else {
41
         } else {
40
             getUrl = room.getExternalAuthUrl(true);
42
             getUrl = room.getExternalAuthUrl(true);
41
         }
43
         }
42
-        getUrl.then(function (url) {
44
+        getUrl.then(url => {
43
             externalAuthWindow = LoginDialog.showExternalAuthDialog(
45
             externalAuthWindow = LoginDialog.showExternalAuthDialog(
44
                 url,
46
                 url,
45
-                function () {
47
+                () => {
46
                     externalAuthWindow = null;
48
                     externalAuthWindow = null;
47
                     if (!isTokenAuthEnabled) {
49
                     if (!isTokenAuthEnabled) {
48
                         room.join(lockPassword);
50
                         room.join(lockPassword);
50
                 }
52
                 }
51
             );
53
             );
52
         });
54
         });
55
+    } else if (isTokenAuthEnabled) {
56
+        redirectToTokenAuthService(room.getName());
53
     } else {
57
     } else {
54
-        // If conference has not been started yet
55
-        // then  redirect to login page
56
-        if (isTokenAuthEnabled) {
57
-            redirectToTokenAuthService(room.getName());
58
-        } else {
59
-            room.getExternalAuthUrl().then(UIUtil.redirect);
60
-        }
58
+        room.getExternalAuthUrl().then(UIUtil.redirect);
61
     }
59
     }
62
 }
60
 }
63
 
61
 
77
  * @param room the name fo the conference room.
75
  * @param room the name fo the conference room.
78
  */
76
  */
79
 function initJWTTokenListener(room) {
77
 function initJWTTokenListener(room) {
80
-    var listener = function ({ data, source }) {
78
+    /**
79
+     *
80
+     */
81
+    function listener({ data, source }) {
81
         if (externalAuthWindow !== source) {
82
         if (externalAuthWindow !== source) {
82
-            logger.warn("Ignored message not coming " +
83
-                "from external authnetication window");
83
+            logger.warn('Ignored message not coming '
84
+                + 'from external authnetication window');
85
+
84
             return;
86
             return;
85
         }
87
         }
86
 
88
 
87
         let jwt;
89
         let jwt;
88
 
90
 
89
         if (data && (jwt = data.jwtToken)) {
91
         if (data && (jwt = data.jwtToken)) {
90
-            logger.info("Received JSON Web Token (JWT):", jwt);
92
+            logger.info('Received JSON Web Token (JWT):', jwt);
91
 
93
 
92
             APP.store.dispatch(setJWT(jwt));
94
             APP.store.dispatch(setJWT(jwt));
93
 
95
 
94
-            var roomName = room.getName();
95
-            openConnection({retry: false, roomName: roomName })
96
-                .then(function (connection) {
97
-                    // Start new connection
98
-                    let newRoom = connection.initJitsiConference(
99
-                        roomName, APP.conference._getConferenceOptions());
100
-                    // Authenticate from the new connection to get
101
-                    // the session-ID from the focus, which wil then be used
102
-                    // to upgrade current connection's user role
103
-                    newRoom.room.moderator.authenticate().then(function () {
104
-                        connection.disconnect();
105
-                        // At this point we'll have session-ID stored in
106
-                        // the settings. It wil be used in the call below
107
-                        // to upgrade user's role
108
-                        room.room.moderator.authenticate()
109
-                            .then(function () {
110
-                                logger.info("User role upgrade done !");
111
-                                unregister();
112
-                            }).catch(function (err, errCode) {
113
-                                logger.error(
114
-                                    "Authentication failed: ", err, errCode);
115
-                                unregister();
116
-                            });
117
-                    }).catch(function (error, code) {
118
-                        unregister();
119
-                        connection.disconnect();
120
-                        logger.error(
121
-                            'Authentication failed on the new connection',
122
-                            error, code);
123
-                    });
124
-                }, function (err) {
96
+            const roomName = room.getName();
97
+
98
+            openConnection({
99
+                retry: false,
100
+                roomName
101
+            }).then(connection => {
102
+                // Start new connection
103
+                const newRoom = connection.initJitsiConference(
104
+                    roomName, APP.conference._getConferenceOptions());
105
+
106
+                // Authenticate from the new connection to get
107
+                // the session-ID from the focus, which wil then be used
108
+                // to upgrade current connection's user role
109
+
110
+                newRoom.room.moderator.authenticate()
111
+                .then(() => {
112
+                    connection.disconnect();
113
+
114
+                    // At this point we'll have session-ID stored in
115
+                    // the settings. It wil be used in the call below
116
+                    // to upgrade user's role
117
+                    room.room.moderator.authenticate()
118
+                        .then(() => {
119
+                            logger.info('User role upgrade done !');
120
+                            // eslint-disable-line no-use-before-define
121
+                            unregister();
122
+                        })
123
+                        .catch((err, errCode) => {
124
+                            logger.error('Authentication failed: ',
125
+                                err, errCode);
126
+                            unregister();
127
+                        });
128
+                })
129
+                .catch((error, code) => {
125
                     unregister();
130
                     unregister();
126
-                    logger.error("Failed to open new connection", err);
131
+                    connection.disconnect();
132
+                    logger.error(
133
+                        'Authentication failed on the new connection',
134
+                        error, code);
127
                 });
135
                 });
136
+            }, err => {
137
+                unregister();
138
+                logger.error('Failed to open new connection', err);
139
+            });
128
         }
140
         }
129
-    };
130
-    var unregister = function () {
131
-        window.removeEventListener("message", listener);
132
-    };
141
+    }
142
+
143
+    /**
144
+     *
145
+     */
146
+    function unregister() {
147
+        window.removeEventListener('message', listener);
148
+    }
149
+
133
     if (window.addEventListener) {
150
     if (window.addEventListener) {
134
-        window.addEventListener("message", listener, false);
151
+        window.addEventListener('message', listener, false);
135
     }
152
     }
136
 }
153
 }
137
 
154
 
183
  * @param {JitsiConference} room
200
  * @param {JitsiConference} room
184
  * @param {string} [lockPassword] password to use if the conference is locked
201
  * @param {string} [lockPassword] password to use if the conference is locked
185
  */
202
  */
186
-function authenticate (room, lockPassword) {
203
+function authenticate(room, lockPassword) {
187
     if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
204
     if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
188
         doExternalAuth(room, lockPassword);
205
         doExternalAuth(room, lockPassword);
189
     } else {
206
     } else {
198
  * @param {string} [lockPassword] password to use if the conference is locked
215
  * @param {string} [lockPassword] password to use if the conference is locked
199
  * @returns {Promise}
216
  * @returns {Promise}
200
  */
217
  */
201
-function logout (room) {
202
-    return new Promise(function (resolve) {
218
+function logout(room) {
219
+    return new Promise(resolve => {
203
         room.room.moderator.logout(resolve);
220
         room.room.moderator.logout(resolve);
204
-    }).then(function (url) {
221
+    }).then(url => {
205
         // de-authenticate conference on the fly
222
         // de-authenticate conference on the fly
206
         if (room.isJoined()) {
223
         if (room.isJoined()) {
207
             room.join();
224
             room.join();
241
     }
258
     }
242
 }
259
 }
243
 
260
 
261
+/**
262
+ *
263
+ */
244
 function showXmppPasswordPrompt(roomName, connect) {
264
 function showXmppPasswordPrompt(roomName, connect) {
245
-    return new Promise(function (resolve, reject) {
246
-        let authDialog = LoginDialog.showAuthDialog(
247
-            function (id, password) {
248
-                connect(id, password, roomName).then(function (connection) {
265
+    return new Promise((resolve, reject) => {
266
+        const authDialog = LoginDialog.showAuthDialog(
267
+            (id, password) => {
268
+                connect(id, password, roomName).then(connection => {
249
                     authDialog.close();
269
                     authDialog.close();
250
                     resolve(connection);
270
                     resolve(connection);
251
-                }, function (err) {
271
+                }, err => {
252
                     if (err === JitsiConnectionErrors.PASSWORD_REQUIRED) {
272
                     if (err === JitsiConnectionErrors.PASSWORD_REQUIRED) {
253
                         authDialog.displayError(err);
273
                         authDialog.displayError(err);
254
                     } else {
274
                     } else {
275
     if (isTokenAuthEnabled) {
295
     if (isTokenAuthEnabled) {
276
         // This Promise never resolves as user gets redirected to another URL
296
         // This Promise never resolves as user gets redirected to another URL
277
         return new Promise(() => redirectToTokenAuthService(roomName));
297
         return new Promise(() => redirectToTokenAuthService(roomName));
278
-    } else {
279
-        return showXmppPasswordPrompt(roomName, connect);
280
     }
298
     }
299
+
300
+    return showXmppPasswordPrompt(roomName, connect);
301
+
281
 }
302
 }
282
 
303
 
283
 export default {
304
 export default {

+ 48
- 38
modules/UI/authentication/LoginDialog.js View File

10
  * @returns {string} html string
10
  * @returns {string} html string
11
  */
11
  */
12
 function getPasswordInputHtml() {
12
 function getPasswordInputHtml() {
13
-    let placeholder = config.hosts.authdomain
14
-        ? "user identity"
15
-        : "user@domain.net";
13
+    const placeholder = config.hosts.authdomain
14
+        ? 'user identity'
15
+        : 'user@domain.net';
16
 
16
 
17
     return `
17
     return `
18
         <input name="username" type="text"
18
         <input name="username" type="text"
29
  */
29
  */
30
 function cancelButton() {
30
 function cancelButton() {
31
     return {
31
     return {
32
-        title: APP.translation.generateTranslationHTML("dialog.Cancel"),
32
+        title: APP.translation.generateTranslationHTML('dialog.Cancel'),
33
         value: false
33
         value: false
34
     };
34
     };
35
 }
35
 }
46
  * @param {function} [cancelCallback] callback to invoke if user canceled.
46
  * @param {function} [cancelCallback] callback to invoke if user canceled.
47
  */
47
  */
48
 function LoginDialog(successCallback, cancelCallback) {
48
 function LoginDialog(successCallback, cancelCallback) {
49
-    let loginButtons = [{
50
-        title: APP.translation.generateTranslationHTML("dialog.Ok"),
49
+    const loginButtons = [ {
50
+        title: APP.translation.generateTranslationHTML('dialog.Ok'),
51
         value: true
51
         value: true
52
-    }];
53
-    let finishedButtons = [{
52
+    } ];
53
+    const finishedButtons = [ {
54
         title: APP.translation.generateTranslationHTML('dialog.retry'),
54
         title: APP.translation.generateTranslationHTML('dialog.retry'),
55
         value: 'retry'
55
         value: 'retry'
56
-    }];
56
+    } ];
57
 
57
 
58
     // show "cancel" button only if cancelCallback provided
58
     // show "cancel" button only if cancelCallback provided
59
     if (cancelCallback) {
59
     if (cancelCallback) {
61
         finishedButtons.push(cancelButton());
61
         finishedButtons.push(cancelButton());
62
     }
62
     }
63
 
63
 
64
+    const connDialog = APP.UI.messageHandler.openDialogWithStates(
65
+        states, // eslint-disable-line no-use-before-define
66
+        {
67
+            persistent: true,
68
+            closeText: ''
69
+        },
70
+        null
71
+    );
72
+
64
     const states = {
73
     const states = {
65
         login: {
74
         login: {
66
             titleKey: 'dialog.passwordRequired',
75
             titleKey: 'dialog.passwordRequired',
67
             html: getPasswordInputHtml(),
76
             html: getPasswordInputHtml(),
68
             buttons: loginButtons,
77
             buttons: loginButtons,
69
             focus: ':input:first',
78
             focus: ':input:first',
70
-            submit: function (e, v, m, f) {
79
+            // eslint-disable-next-line max-params
80
+            submit(e, v, m, f) {
71
                 e.preventDefault();
81
                 e.preventDefault();
72
                 if (v) {
82
                 if (v) {
73
-                    let jid = f.username;
74
-                    let password = f.password;
83
+                    const jid = f.username;
84
+                    const password = f.password;
85
+
75
                     if (jid && password) {
86
                     if (jid && password) {
76
                         connDialog.goToState('connecting');
87
                         connDialog.goToState('connecting');
77
                         successCallback(toJid(jid, config.hosts), password);
88
                         successCallback(toJid(jid, config.hosts), password);
84
         },
95
         },
85
         connecting: {
96
         connecting: {
86
             titleKey: 'dialog.connecting',
97
             titleKey: 'dialog.connecting',
87
-            html:   '<div id="connectionStatus"></div>',
98
+            html: '<div id="connectionStatus"></div>',
88
             buttons: [],
99
             buttons: [],
89
             defaultButton: 0
100
             defaultButton: 0
90
         },
101
         },
91
         finished: {
102
         finished: {
92
             titleKey: 'dialog.error',
103
             titleKey: 'dialog.error',
93
-            html:   '<div id="errorMessage"></div>',
104
+            html: '<div id="errorMessage"></div>',
94
             buttons: finishedButtons,
105
             buttons: finishedButtons,
95
             defaultButton: 0,
106
             defaultButton: 0,
96
-            submit: function (e, v) {
107
+            submit(e, v) {
97
                 e.preventDefault();
108
                 e.preventDefault();
98
                 if (v === 'retry') {
109
                 if (v === 'retry') {
99
                     connDialog.goToState('login');
110
                     connDialog.goToState('login');
105
         }
116
         }
106
     };
117
     };
107
 
118
 
108
-    var connDialog = APP.UI.messageHandler.openDialogWithStates(
109
-        states, { persistent: true, closeText: '' }, null
110
-    );
111
-
112
     /**
119
     /**
113
      * Displays error message in 'finished' state which allows either to cancel
120
      * Displays error message in 'finished' state which allows either to cancel
114
      * or retry.
121
      * or retry.
115
      * @param error the key to the error to be displayed.
122
      * @param error the key to the error to be displayed.
116
      * @param options the options to the error message (optional)
123
      * @param options the options to the error message (optional)
117
      */
124
      */
118
-    this.displayError = function (error, options) {
125
+    this.displayError = function(error, options) {
119
 
126
 
120
-        let finishedState = connDialog.getState('finished');
127
+        const finishedState = connDialog.getState('finished');
121
 
128
 
122
-        let errorMessageElem = finishedState.find('#errorMessage');
129
+        const errorMessageElem = finishedState.find('#errorMessage');
123
 
130
 
124
         let messageKey;
131
         let messageKey;
132
+
125
         if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
133
         if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
126
             // this is a password required error, as login window was already
134
             // this is a password required error, as login window was already
127
             // open once, this means username or password is wrong
135
             // open once, this means username or password is wrong
128
             messageKey = 'dialog.incorrectPassword';
136
             messageKey = 'dialog.incorrectPassword';
129
-        }
130
-        else {
137
+        } else {
131
             messageKey = 'dialog.connectErrorWithMsg';
138
             messageKey = 'dialog.connectErrorWithMsg';
132
 
139
 
133
-            if (!options)
134
-                options = {};
140
+            if (!options) {
141
+                options = {};// eslint-disable-line no-param-reassign
142
+            }
135
 
143
 
136
             options.msg = error;
144
             options.msg = error;
137
         }
145
         }
138
 
146
 
139
-        errorMessageElem.attr("data-i18n", messageKey);
147
+        errorMessageElem.attr('data-i18n', messageKey);
140
 
148
 
141
         APP.translation.translateElement($(errorMessageElem), options);
149
         APP.translation.translateElement($(errorMessageElem), options);
142
 
150
 
147
      *  Show message as connection status.
155
      *  Show message as connection status.
148
      * @param {string} messageKey the key to the message
156
      * @param {string} messageKey the key to the message
149
      */
157
      */
150
-    this.displayConnectionStatus = function (messageKey) {
151
-        let connectingState = connDialog.getState('connecting');
158
+    this.displayConnectionStatus = function(messageKey) {
159
+        const connectingState = connDialog.getState('connecting');
152
 
160
 
153
-        let connectionStatus = connectingState.find('#connectionStatus');
154
-        connectionStatus.attr("data-i18n", messageKey);
161
+        const connectionStatus = connectingState.find('#connectionStatus');
162
+
163
+        connectionStatus.attr('data-i18n', messageKey);
155
         APP.translation.translateElement($(connectionStatus));
164
         APP.translation.translateElement($(connectionStatus));
156
     };
165
     };
157
 
166
 
158
     /**
167
     /**
159
      * Closes LoginDialog.
168
      * Closes LoginDialog.
160
      */
169
      */
161
-    this.close = function () {
170
+    this.close = function() {
162
         connDialog.close();
171
         connDialog.close();
163
     };
172
     };
164
 }
173
 }
173
      *
182
      *
174
      * @returns {LoginDialog}
183
      * @returns {LoginDialog}
175
      */
184
      */
176
-    showAuthDialog: function (successCallback, cancelCallback) {
185
+    showAuthDialog(successCallback, cancelCallback) {
177
         return new LoginDialog(successCallback, cancelCallback);
186
         return new LoginDialog(successCallback, cancelCallback);
178
     },
187
     },
179
 
188
 
183
      * @param {function} callback callback to invoke when auth popup is closed.
192
      * @param {function} callback callback to invoke when auth popup is closed.
184
      * @returns auth dialog
193
      * @returns auth dialog
185
      */
194
      */
186
-    showExternalAuthDialog: function (url, callback) {
187
-        var dialog = APP.UI.messageHandler.openCenteredPopup(
195
+    showExternalAuthDialog(url, callback) {
196
+        const dialog = APP.UI.messageHandler.openCenteredPopup(
188
             url, 910, 660,
197
             url, 910, 660,
198
+
189
             // On closed
199
             // On closed
190
             callback
200
             callback
191
         );
201
         );
192
 
202
 
193
         if (!dialog) {
203
         if (!dialog) {
194
-            APP.UI.messageHandler.openMessageDialog(null, "dialog.popupError");
204
+            APP.UI.messageHandler.openMessageDialog(null, 'dialog.popupError');
195
         }
205
         }
196
 
206
 
197
         return dialog;
207
         return dialog;
215
         const buttonTxt = APP.translation.generateTranslationHTML(
225
         const buttonTxt = APP.translation.generateTranslationHTML(
216
             'dialog.IamHost'
226
             'dialog.IamHost'
217
         );
227
         );
218
-        const buttons = [{
228
+        const buttons = [ {
219
             title: buttonTxt,
229
             title: buttonTxt,
220
             value: 'authNow'
230
             value: 'authNow'
221
-        }];
231
+        } ];
222
 
232
 
223
         return APP.UI.messageHandler.openDialog(
233
         return APP.UI.messageHandler.openDialog(
224
             'dialog.WaitingForHost',
234
             'dialog.WaitingForHost',

+ 17
- 13
modules/UI/avatar/Avatar.js View File

25
 
25
 
26
 import { getAvatarURL } from '../../../react/features/base/participants';
26
 import { getAvatarURL } from '../../../react/features/base/participants';
27
 
27
 
28
-let users = {};
28
+const users = {};
29
 
29
 
30
 export default {
30
 export default {
31
     /**
31
     /**
34
      * @param prop {string} name of the prop
34
      * @param prop {string} name of the prop
35
      * @param val {string} value to be set
35
      * @param val {string} value to be set
36
      */
36
      */
37
-    _setUserProp: function (id, prop, val) {
37
+    _setUserProp(id, prop, val) {
38
         // FIXME: Fixes the issue with not be able to return avatar for the
38
         // FIXME: Fixes the issue with not be able to return avatar for the
39
         // local user when the conference has been left. Maybe there is beter
39
         // local user when the conference has been left. Maybe there is beter
40
         // way to solve it.
40
         // way to solve it.
41
-        if(!id || APP.conference.isLocalId(id)) {
42
-            id = "local";
41
+        if (!id || APP.conference.isLocalId(id)) {
42
+            id = 'local';// eslint-disable-line no-param-reassign
43
         }
43
         }
44
-        if(!val || (users[id] && users[id][prop] === val))
44
+        if (!val || (users[id] && users[id][prop] === val)) {
45
             return;
45
             return;
46
-        if(!users[id])
46
+        }
47
+        if (!users[id]) {
47
             users[id] = {};
48
             users[id] = {};
49
+        }
48
         users[id][prop] = val;
50
         users[id][prop] = val;
49
     },
51
     },
50
 
52
 
54
      * @param id id of the user
56
      * @param id id of the user
55
      * @param email email or nickname to be used as a hash
57
      * @param email email or nickname to be used as a hash
56
      */
58
      */
57
-    setUserEmail: function (id, email) {
58
-        this._setUserProp(id, "email", email);
59
+    setUserEmail(id, email) {
60
+        this._setUserProp(id, 'email', email);
59
     },
61
     },
60
 
62
 
61
     /**
63
     /**
64
      * @param id id of the user
66
      * @param id id of the user
65
      * @param url the url for the avatar
67
      * @param url the url for the avatar
66
      */
68
      */
67
-    setUserAvatarUrl: function (id, url) {
68
-        this._setUserProp(id, "avatarUrl", url);
69
+    setUserAvatarUrl(id, url) {
70
+        this._setUserProp(id, 'avatarUrl', url);
69
     },
71
     },
70
 
72
 
71
     /**
73
     /**
73
      * @param id id of the user
75
      * @param id id of the user
74
      * @param avatarId an id to be used for the avatar
76
      * @param avatarId an id to be used for the avatar
75
      */
77
      */
76
-    setUserAvatarID: function (id, avatarId) {
77
-        this._setUserProp(id, "avatarId", avatarId);
78
+    setUserAvatarID(id, avatarId) {
79
+        this._setUserProp(id, 'avatarId', avatarId);
78
     },
80
     },
79
 
81
 
80
     /**
82
     /**
82
      * identified by its id.
84
      * identified by its id.
83
      * @param {string} userId user id
85
      * @param {string} userId user id
84
      */
86
      */
85
-    getAvatarUrl: function (userId) {
87
+    getAvatarUrl(userId) {
86
         let user;
88
         let user;
89
+
87
         if (!userId || APP.conference.isLocalId(userId)) {
90
         if (!userId || APP.conference.isLocalId(userId)) {
88
             user = users.local;
91
             user = users.local;
92
+            // eslint-disable-next-line no-param-reassign
89
             userId = APP.conference.getMyUserId();
93
             userId = APP.conference.getMyUserId();
90
         } else {
94
         } else {
91
             user = users[userId];
95
             user = users[userId];

+ 81
- 43
modules/UI/etherpad/Etherpad.js View File

1
 /* global $ */
1
 /* global $ */
2
 
2
 
3
-import VideoLayout from "../videolayout/VideoLayout";
3
+import VideoLayout from '../videolayout/VideoLayout';
4
 import LargeContainer from '../videolayout/LargeContainer';
4
 import LargeContainer from '../videolayout/LargeContainer';
5
-import UIEvents from "../../../service/UI/UIEvents";
5
+import UIEvents from '../../../service/UI/UIEvents';
6
 import Filmstrip from '../videolayout/Filmstrip';
6
 import Filmstrip from '../videolayout/Filmstrip';
7
 
7
 
8
 /**
8
 /**
15
     useMonospaceFont: false
15
     useMonospaceFont: false
16
 });
16
 });
17
 
17
 
18
-function bubbleIframeMouseMove(iframe){
19
-    var existingOnMouseMove = iframe.contentWindow.onmousemove;
20
-    iframe.contentWindow.onmousemove = function(e){
21
-        if(existingOnMouseMove) existingOnMouseMove(e);
22
-        var evt = document.createEvent("MouseEvents");
23
-        var boundingClientRect = iframe.getBoundingClientRect();
18
+/**
19
+ *
20
+ */
21
+function bubbleIframeMouseMove(iframe) {
22
+    const existingOnMouseMove = iframe.contentWindow.onmousemove;
23
+
24
+    iframe.contentWindow.onmousemove = function(e) {
25
+        if (existingOnMouseMove) {
26
+            existingOnMouseMove(e);
27
+        }
28
+        const evt = document.createEvent('MouseEvents');
29
+        const boundingClientRect = iframe.getBoundingClientRect();
30
+
24
         evt.initMouseEvent(
31
         evt.initMouseEvent(
25
-            "mousemove",
32
+            'mousemove',
26
             true, // bubbles
33
             true, // bubbles
27
             false, // not cancelable
34
             false, // not cancelable
28
             window,
35
             window,
46
  * Default Etherpad frame width.
53
  * Default Etherpad frame width.
47
  */
54
  */
48
 const DEFAULT_WIDTH = 640;
55
 const DEFAULT_WIDTH = 640;
56
+
49
 /**
57
 /**
50
  * Default Etherpad frame height.
58
  * Default Etherpad frame height.
51
  */
59
  */
52
 const DEFAULT_HEIGHT = 480;
60
 const DEFAULT_HEIGHT = 480;
53
 
61
 
54
-const ETHERPAD_CONTAINER_TYPE = "etherpad";
62
+const ETHERPAD_CONTAINER_TYPE = 'etherpad';
55
 
63
 
56
 /**
64
 /**
57
  * Container for Etherpad iframe.
65
  * Container for Etherpad iframe.
58
  */
66
  */
59
 class Etherpad extends LargeContainer {
67
 class Etherpad extends LargeContainer {
60
-
61
-    constructor (domain, name) {
68
+    /**
69
+     * Creates new Etherpad object
70
+     */
71
+    constructor(domain, name) {
62
         super();
72
         super();
63
 
73
 
64
         const iframe = document.createElement('iframe');
74
         const iframe = document.createElement('iframe');
65
 
75
 
66
-        iframe.id = "etherpadIFrame";
67
-        iframe.src = domain + name + '?' + options;
76
+        iframe.id = 'etherpadIFrame';
77
+        iframe.src = `${domain + name}?${options}`;
68
         iframe.frameBorder = 0;
78
         iframe.frameBorder = 0;
69
-        iframe.scrolling = "no";
79
+        iframe.scrolling = 'no';
70
         iframe.width = DEFAULT_WIDTH;
80
         iframe.width = DEFAULT_WIDTH;
71
         iframe.height = DEFAULT_HEIGHT;
81
         iframe.height = DEFAULT_HEIGHT;
72
         iframe.setAttribute('style', 'visibility: hidden;');
82
         iframe.setAttribute('style', 'visibility: hidden;');
77
             document.domain = document.domain;
87
             document.domain = document.domain;
78
             bubbleIframeMouseMove(iframe);
88
             bubbleIframeMouseMove(iframe);
79
 
89
 
80
-            setTimeout(function() {
90
+            setTimeout(() => {
81
                 const doc = iframe.contentDocument;
91
                 const doc = iframe.contentDocument;
82
 
92
 
83
                 // the iframes inside of the etherpad are
93
                 // the iframes inside of the etherpad are
84
                 // not yet loaded when the etherpad iframe is loaded
94
                 // not yet loaded when the etherpad iframe is loaded
85
-                const outer = doc.getElementsByName("ace_outer")[0];
95
+                const outer = doc.getElementsByName('ace_outer')[0];
96
+
86
                 bubbleIframeMouseMove(outer);
97
                 bubbleIframeMouseMove(outer);
87
 
98
 
88
-                const inner = doc.getElementsByName("ace_inner")[0];
99
+                const inner = doc.getElementsByName('ace_inner')[0];
100
+
89
                 bubbleIframeMouseMove(inner);
101
                 bubbleIframeMouseMove(inner);
90
             }, 2000);
102
             }, 2000);
91
         };
103
         };
93
         this.iframe = iframe;
105
         this.iframe = iframe;
94
     }
106
     }
95
 
107
 
96
-    get isOpen () {
97
-        return !!this.iframe;
108
+    /**
109
+     *
110
+     */
111
+    get isOpen() {
112
+        return Boolean(this.iframe);
98
     }
113
     }
99
 
114
 
100
-    get container () {
115
+    /**
116
+     *
117
+     */
118
+    get container() {
101
         return document.getElementById('etherpad');
119
         return document.getElementById('etherpad');
102
     }
120
     }
103
 
121
 
104
-    // eslint-disable-next-line no-unused-vars
105
-    resize (containerWidth, containerHeight, animate) {
106
-        let height = containerHeight - Filmstrip.getFilmstripHeight();
107
-        let width = containerWidth;
122
+    /**
123
+     *
124
+     */
125
+    resize(containerWidth, containerHeight) {
126
+        const height = containerHeight - Filmstrip.getFilmstripHeight();
127
+        const width = containerWidth;
108
 
128
 
109
-        $(this.iframe).width(width).height(height);
129
+        $(this.iframe)
130
+            .width(width)
131
+            .height(height);
110
     }
132
     }
111
 
133
 
112
-    show () {
134
+    /**
135
+     *
136
+     */
137
+    show() {
113
         const $iframe = $(this.iframe);
138
         const $iframe = $(this.iframe);
114
         const $container = $(this.container);
139
         const $container = $(this.container);
115
-        let self = this;
140
+        const self = this;
116
 
141
 
117
         return new Promise(resolve => {
142
         return new Promise(resolve => {
118
-            $iframe.fadeIn(300, function () {
143
+            $iframe.fadeIn(300, () => {
119
                 self.bodyBackground = document.body.style.background;
144
                 self.bodyBackground = document.body.style.background;
120
                 document.body.style.background = '#eeeeee';
145
                 document.body.style.background = '#eeeeee';
121
-                $iframe.css({visibility: 'visible'});
122
-                $container.css({zIndex: 2});
146
+                $iframe.css({ visibility: 'visible' });
147
+                $container.css({ zIndex: 2 });
123
                 resolve();
148
                 resolve();
124
             });
149
             });
125
         });
150
         });
126
     }
151
     }
127
 
152
 
128
-    hide () {
153
+    /**
154
+     *
155
+     */
156
+    hide() {
129
         const $iframe = $(this.iframe);
157
         const $iframe = $(this.iframe);
130
         const $container = $(this.container);
158
         const $container = $(this.container);
159
+
131
         document.body.style.background = this.bodyBackground;
160
         document.body.style.background = this.bodyBackground;
132
 
161
 
133
         return new Promise(resolve => {
162
         return new Promise(resolve => {
134
-            $iframe.fadeOut(300, function () {
135
-                $iframe.css({visibility: 'hidden'});
136
-                $container.css({zIndex: 0});
163
+            $iframe.fadeOut(300, () => {
164
+                $iframe.css({ visibility: 'hidden' });
165
+                $container.css({ zIndex: 0 });
137
                 resolve();
166
                 resolve();
138
             });
167
             });
139
         });
168
         });
142
     /**
171
     /**
143
      * @return {boolean} do not switch on dominant speaker event if on stage.
172
      * @return {boolean} do not switch on dominant speaker event if on stage.
144
      */
173
      */
145
-    stayOnStage () {
174
+    stayOnStage() {
146
         return true;
175
         return true;
147
     }
176
     }
148
 }
177
 }
151
  * Manager of the Etherpad frame.
180
  * Manager of the Etherpad frame.
152
  */
181
  */
153
 export default class EtherpadManager {
182
 export default class EtherpadManager {
154
-    constructor (domain, name, eventEmitter) {
183
+    /**
184
+     *
185
+     */
186
+    constructor(domain, name, eventEmitter) {
155
         if (!domain || !name) {
187
         if (!domain || !name) {
156
-            throw new Error("missing domain or name");
188
+            throw new Error('missing domain or name');
157
         }
189
         }
158
 
190
 
159
         this.domain = domain;
191
         this.domain = domain;
162
         this.etherpad = null;
194
         this.etherpad = null;
163
     }
195
     }
164
 
196
 
165
-    get isOpen () {
166
-        return !!this.etherpad;
197
+    /**
198
+     *
199
+     */
200
+    get isOpen() {
201
+        return Boolean(this.etherpad);
167
     }
202
     }
168
 
203
 
204
+    /**
205
+     * 
206
+     */
169
     isVisible() {
207
     isVisible() {
170
         return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
208
         return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
171
     }
209
     }
173
     /**
211
     /**
174
      * Create new Etherpad frame.
212
      * Create new Etherpad frame.
175
      */
213
      */
176
-    openEtherpad () {
214
+    openEtherpad() {
177
         this.etherpad = new Etherpad(this.domain, this.name);
215
         this.etherpad = new Etherpad(this.domain, this.name);
178
         VideoLayout.addLargeVideoContainer(
216
         VideoLayout.addLargeVideoContainer(
179
             ETHERPAD_CONTAINER_TYPE,
217
             ETHERPAD_CONTAINER_TYPE,
185
      * Toggle Etherpad frame visibility.
223
      * Toggle Etherpad frame visibility.
186
      * Open new Etherpad frame if there is no Etherpad frame yet.
224
      * Open new Etherpad frame if there is no Etherpad frame yet.
187
      */
225
      */
188
-    toggleEtherpad () {
226
+    toggleEtherpad() {
189
         if (!this.isOpen) {
227
         if (!this.isOpen) {
190
             this.openEtherpad();
228
             this.openEtherpad();
191
         }
229
         }
192
 
230
 
193
-        let isVisible = this.isVisible();
231
+        const isVisible = this.isVisible();
194
 
232
 
195
         VideoLayout.showLargeVideoContainer(
233
         VideoLayout.showLargeVideoContainer(
196
             ETHERPAD_CONTAINER_TYPE, !isVisible);
234
             ETHERPAD_CONTAINER_TYPE, !isVisible);

+ 97
- 75
modules/UI/recording/Recording.js View File

14
  * See the License for the specific language governing permissions and
14
  * See the License for the specific language governing permissions and
15
  * limitations under the License.
15
  * limitations under the License.
16
  */
16
  */
17
-const logger = require("jitsi-meet-logger").getLogger(__filename);
17
+const logger = require('jitsi-meet-logger').getLogger(__filename);
18
 
18
 
19
-import UIEvents from "../../../service/UI/UIEvents";
19
+import UIEvents from '../../../service/UI/UIEvents';
20
 import UIUtil from '../util/UIUtil';
20
 import UIUtil from '../util/UIUtil';
21
 import VideoLayout from '../videolayout/VideoLayout';
21
 import VideoLayout from '../videolayout/VideoLayout';
22
 
22
 
84
  */
84
  */
85
 function _isRecordingButtonEnabled() {
85
 function _isRecordingButtonEnabled() {
86
     return (
86
     return (
87
-        interfaceConfig.TOOLBAR_BUTTONS.indexOf("recording") !== -1
87
+        interfaceConfig.TOOLBAR_BUTTONS.indexOf('recording') !== -1
88
             && config.enableRecording
88
             && config.enableRecording
89
             && APP.conference.isRecordingSupported());
89
             && APP.conference.isRecordingSupported());
90
 }
90
 }
95
  */
95
  */
96
 function _requestLiveStreamId() {
96
 function _requestLiveStreamId() {
97
     const cancelButton
97
     const cancelButton
98
-        = APP.translation.generateTranslationHTML("dialog.Cancel");
99
-    const backButton = APP.translation.generateTranslationHTML("dialog.Back");
98
+        = APP.translation.generateTranslationHTML('dialog.Cancel');
99
+    const backButton = APP.translation.generateTranslationHTML('dialog.Back');
100
     const startStreamingButton
100
     const startStreamingButton
101
-        = APP.translation.generateTranslationHTML("dialog.startLiveStreaming");
101
+        = APP.translation.generateTranslationHTML('dialog.startLiveStreaming');
102
     const streamIdRequired
102
     const streamIdRequired
103
         = APP.translation.generateTranslationHTML(
103
         = APP.translation.generateTranslationHTML(
104
-            "liveStreaming.streamIdRequired");
104
+            'liveStreaming.streamIdRequired');
105
     const streamIdHelp
105
     const streamIdHelp
106
         = APP.translation.generateTranslationHTML(
106
         = APP.translation.generateTranslationHTML(
107
-            "liveStreaming.streamIdHelp");
107
+            'liveStreaming.streamIdHelp');
108
 
108
 
109
-    return new Promise(function (resolve, reject) {
109
+    return new Promise((resolve, reject) => {
110
         dialog = APP.UI.messageHandler.openDialogWithStates({
110
         dialog = APP.UI.messageHandler.openDialogWithStates({
111
             state0: {
111
             state0: {
112
-                titleKey: "dialog.liveStreaming",
112
+                titleKey: 'dialog.liveStreaming',
113
                 html:
113
                 html:
114
                     `<input  class="input-control"
114
                     `<input  class="input-control"
115
                     name="streamId" type="text"
115
                     name="streamId" type="text"
116
                     data-i18n="[placeholder]dialog.streamKey"
116
                     data-i18n="[placeholder]dialog.streamKey"
117
                     autofocus><div style="text-align: right">
117
                     autofocus><div style="text-align: right">
118
                     <a class="helper-link" target="_new"
118
                     <a class="helper-link" target="_new"
119
-                    href="${interfaceConfig.LIVE_STREAMING_HELP_LINK}">`
120
-                        + streamIdHelp
121
-                        + `</a></div>`,
119
+                    href="${interfaceConfig.LIVE_STREAMING_HELP_LINK}">${
120
+    streamIdHelp
121
+}</a></div>`,
122
                 persistent: false,
122
                 persistent: false,
123
                 buttons: [
123
                 buttons: [
124
-                    {title: cancelButton, value: false},
125
-                    {title: startStreamingButton, value: true}
124
+                    { title: cancelButton,
125
+                        value: false },
126
+                    { title: startStreamingButton,
127
+                        value: true }
126
                 ],
128
                 ],
127
                 focus: ':input:first',
129
                 focus: ':input:first',
128
                 defaultButton: 1,
130
                 defaultButton: 1,
129
-                submit: function (e, v, m, f) {
131
+                submit(e, v, m, f) { // eslint-disable-line max-params
130
                     e.preventDefault();
132
                     e.preventDefault();
131
 
133
 
132
                     if (v) {
134
                     if (v) {
133
                         if (f.streamId && f.streamId.length > 0) {
135
                         if (f.streamId && f.streamId.length > 0) {
134
                             resolve(UIUtil.escapeHtml(f.streamId));
136
                             resolve(UIUtil.escapeHtml(f.streamId));
135
                             dialog.close();
137
                             dialog.close();
138
+
136
                             return;
139
                             return;
137
                         }
140
                         }
138
-                        else {
139
-                            dialog.goToState('state1');
140
-                            return false;
141
-                        }
142
-                    } else {
143
-                        reject(APP.UI.messageHandler.CANCEL);
144
-                        dialog.close();
141
+                        dialog.goToState('state1');
142
+
145
                         return false;
143
                         return false;
144
+
146
                     }
145
                     }
146
+                    reject(APP.UI.messageHandler.CANCEL);
147
+                    dialog.close();
148
+
149
+                    return false;
150
+
147
                 }
151
                 }
148
             },
152
             },
149
 
153
 
150
             state1: {
154
             state1: {
151
-                titleKey: "dialog.liveStreaming",
155
+                titleKey: 'dialog.liveStreaming',
152
                 html: streamIdRequired,
156
                 html: streamIdRequired,
153
                 persistent: false,
157
                 persistent: false,
154
                 buttons: [
158
                 buttons: [
155
-                    {title: cancelButton, value: false},
156
-                    {title: backButton, value: true}
159
+                    { title: cancelButton,
160
+                        value: false },
161
+                    { title: backButton,
162
+                        value: true }
157
                 ],
163
                 ],
158
                 focus: ':input:first',
164
                 focus: ':input:first',
159
                 defaultButton: 1,
165
                 defaultButton: 1,
160
-                submit: function (e, v) {
166
+                submit(e, v) {
161
                     e.preventDefault();
167
                     e.preventDefault();
162
                     if (v === 0) {
168
                     if (v === 0) {
163
                         reject(APP.UI.messageHandler.CANCEL);
169
                         reject(APP.UI.messageHandler.CANCEL);
168
                 }
174
                 }
169
             }
175
             }
170
         }, {
176
         }, {
171
-            close: function () {
177
+            close() {
172
                 dialog = null;
178
                 dialog = null;
173
             }
179
             }
174
         });
180
         });
180
  * @returns {Promise}
186
  * @returns {Promise}
181
  */
187
  */
182
 function _requestRecordingToken() {
188
 function _requestRecordingToken() {
183
-    let titleKey = "dialog.recordingToken";
184
-    let msgString = (
185
-        `<input name="recordingToken" type="text"
189
+    const titleKey = 'dialog.recordingToken';
190
+    const msgString
191
+        = `<input name="recordingToken" type="text"
186
                 data-i18n="[placeholder]dialog.token"
192
                 data-i18n="[placeholder]dialog.token"
187
                 class="input-control"
193
                 class="input-control"
188
                 autofocus>`
194
                 autofocus>`
189
-    );
190
-    return new Promise(function (resolve, reject) {
195
+
196
+    ;
197
+
198
+
199
+    return new Promise((resolve, reject) => {
191
         dialog = APP.UI.messageHandler.openTwoButtonDialog({
200
         dialog = APP.UI.messageHandler.openTwoButtonDialog({
192
             titleKey,
201
             titleKey,
193
             msgString,
202
             msgString,
194
             leftButtonKey: 'dialog.Save',
203
             leftButtonKey: 'dialog.Save',
195
-            submitFunction: function (e, v, m, f) {
204
+            submitFunction(e, v, m, f) { // eslint-disable-line max-params
196
                 if (v && f.recordingToken) {
205
                 if (v && f.recordingToken) {
197
                     resolve(UIUtil.escapeHtml(f.recordingToken));
206
                     resolve(UIUtil.escapeHtml(f.recordingToken));
198
                 } else {
207
                 } else {
199
                     reject(APP.UI.messageHandler.CANCEL);
208
                     reject(APP.UI.messageHandler.CANCEL);
200
                 }
209
                 }
201
             },
210
             },
202
-            closeFunction: function () {
211
+            closeFunction() {
203
                 dialog = null;
212
                 dialog = null;
204
             },
213
             },
205
             focus: ':input:first'
214
             focus: ':input:first'
215
  * @private
224
  * @private
216
  */
225
  */
217
 function _showStopRecordingPrompt(recordingType) {
226
 function _showStopRecordingPrompt(recordingType) {
218
-    var title;
219
-    var message;
220
-    var buttonKey;
221
-    if (recordingType === "jibri") {
222
-        title = "dialog.liveStreaming";
223
-        message = "dialog.stopStreamingWarning";
224
-        buttonKey = "dialog.stopLiveStreaming";
225
-    }
226
-    else {
227
-        title = "dialog.recording";
228
-        message = "dialog.stopRecordingWarning";
229
-        buttonKey = "dialog.stopRecording";
227
+    let title;
228
+    let message;
229
+    let buttonKey;
230
+
231
+    if (recordingType === 'jibri') {
232
+        title = 'dialog.liveStreaming';
233
+        message = 'dialog.stopStreamingWarning';
234
+        buttonKey = 'dialog.stopLiveStreaming';
235
+    } else {
236
+        title = 'dialog.recording';
237
+        message = 'dialog.stopRecordingWarning';
238
+        buttonKey = 'dialog.stopRecording';
230
     }
239
     }
231
 
240
 
232
     return new Promise((resolve, reject) => {
241
     return new Promise((resolve, reject) => {
248
  * @returns {boolean} true if the condition is met or false otherwise.
257
  * @returns {boolean} true if the condition is met or false otherwise.
249
  */
258
  */
250
 function isStartingStatus(status) {
259
 function isStartingStatus(status) {
251
-    return status === JitsiRecordingStatus.PENDING || status === JitsiRecordingStatus.RETRYING;
260
+    return (
261
+        status === JitsiRecordingStatus.PENDING
262
+            || status === JitsiRecordingStatus.RETRYING
263
+    );
252
 }
264
 }
253
 
265
 
254
 /**
266
 /**
256
  * @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
268
  * @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
257
  * updateRecordingUI, checkAutoRecord}}
269
  * updateRecordingUI, checkAutoRecord}}
258
  */
270
  */
259
-var Recording = {
271
+const Recording = {
260
     /**
272
     /**
261
      * Initializes the recording UI.
273
      * Initializes the recording UI.
262
      */
274
      */
267
         this.updateRecordingState(APP.conference.getRecordingState());
279
         this.updateRecordingState(APP.conference.getRecordingState());
268
 
280
 
269
         if (recordingType === 'jibri') {
281
         if (recordingType === 'jibri') {
270
-            this.baseClass = "fa fa-play-circle";
282
+            this.baseClass = 'fa fa-play-circle';
271
             Object.assign(this, STREAMING_TRANSLATION_KEYS);
283
             Object.assign(this, STREAMING_TRANSLATION_KEYS);
272
-        }
273
-        else {
274
-            this.baseClass = "icon-recEnable";
284
+        } else {
285
+            this.baseClass = 'icon-recEnable';
275
             Object.assign(this, RECORDING_TRANSLATION_KEYS);
286
             Object.assign(this, RECORDING_TRANSLATION_KEYS);
276
         }
287
         }
277
 
288
 
301
         const selector = $('#toolbar_button_record');
312
         const selector = $('#toolbar_button_record');
302
 
313
 
303
         selector.addClass(this.baseClass);
314
         selector.addClass(this.baseClass);
304
-        selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
315
+        selector.attr('data-i18n', `[content]${this.recordingButtonTooltip}`);
305
         APP.translation.translateElement(selector);
316
         APP.translation.translateElement(selector);
306
     },
317
     },
307
 
318
 
310
      * @param show {true} to show the recording button, {false} to hide it
321
      * @param show {true} to show the recording button, {false} to hide it
311
      */
322
      */
312
     showRecordingButton(show) {
323
     showRecordingButton(show) {
313
-        let shouldShow = show && _isRecordingButtonEnabled();
314
-        let id = 'toolbar_button_record';
324
+        const shouldShow = show && _isRecordingButtonEnabled();
325
+        const id = 'toolbar_button_record';
315
 
326
 
316
         UIUtil.setVisible(id, shouldShow);
327
         UIUtil.setVisible(id, shouldShow);
317
     },
328
     },
322
      */
333
      */
323
     updateRecordingState(recordingState) {
334
     updateRecordingState(recordingState) {
324
         // I'm the recorder, so I don't want to see any UI related to states.
335
         // I'm the recorder, so I don't want to see any UI related to states.
325
-        if (config.iAmRecorder)
336
+        if (config.iAmRecorder) {
326
             return;
337
             return;
338
+        }
327
 
339
 
328
         // If there's no state change, we ignore the update.
340
         // If there's no state change, we ignore the update.
329
-        if (!recordingState || this.currentState === recordingState)
341
+        if (!recordingState || this.currentState === recordingState) {
330
             return;
342
             return;
343
+        }
331
 
344
 
332
         this.updateRecordingUI(recordingState);
345
         this.updateRecordingUI(recordingState);
333
     },
346
     },
338
      */
351
      */
339
     updateRecordingUI(recordingState) {
352
     updateRecordingUI(recordingState) {
340
 
353
 
341
-        let oldState = this.currentState;
354
+        const oldState = this.currentState;
355
+
342
         this.currentState = recordingState;
356
         this.currentState = recordingState;
343
 
357
 
344
         let labelDisplayConfiguration;
358
         let labelDisplayConfiguration;
366
             // We don't want UI changes if this is an availability change.
380
             // We don't want UI changes if this is an availability change.
367
             if (oldState !== JitsiRecordingStatus.ON && !wasInStartingStatus) {
381
             if (oldState !== JitsiRecordingStatus.ON && !wasInStartingStatus) {
368
                 APP.store.dispatch(updateRecordingState({ recordingState }));
382
                 APP.store.dispatch(updateRecordingState({ recordingState }));
383
+
369
                 return;
384
                 return;
370
             }
385
             }
371
 
386
 
378
 
393
 
379
             this._setToolbarButtonToggled(false);
394
             this._setToolbarButtonToggled(false);
380
 
395
 
381
-            setTimeout(function(){
396
+            setTimeout(() => {
382
                 APP.store.dispatch(hideRecordingLabel());
397
                 APP.store.dispatch(hideRecordingLabel());
383
             }, 5000);
398
             }, 5000);
384
 
399
 
408
         }
423
         }
409
 
424
 
410
         // Return an empty label display configuration to indicate no label
425
         // Return an empty label display configuration to indicate no label
411
-        // should be displayed. The JitsiRecordingStatus.AVAIABLE case is handled here.
426
+        // should be displayed. The JitsiRecordingStatus.AVAIABLE case is
427
+        // handled here.
412
         default: {
428
         default: {
413
             labelDisplayConfiguration = null;
429
             labelDisplayConfiguration = null;
414
         }
430
         }
450
                     this.eventEmitter.emit(UIEvents.RECORDING_TOGGLED);
466
                     this.eventEmitter.emit(UIEvents.RECORDING_TOGGLED);
451
                     sendEvent('recording.stopped');
467
                     sendEvent('recording.stopped');
452
                 },
468
                 },
453
-                () => {});
469
+                () => {}); // eslint-disable-line no-empty-function
454
             break;
470
             break;
455
         }
471
         }
456
         case JitsiRecordingStatus.AVAILABLE:
472
         case JitsiRecordingStatus.AVAILABLE:
457
         case JitsiRecordingStatus.OFF: {
473
         case JitsiRecordingStatus.OFF: {
458
-            if (this.recordingType === 'jibri')
459
-                _requestLiveStreamId().then(streamId => {
474
+            if (this.recordingType === 'jibri') {
475
+                _requestLiveStreamId()
476
+                .then(streamId => {
460
                     this.eventEmitter.emit(
477
                     this.eventEmitter.emit(
461
                         UIEvents.RECORDING_TOGGLED,
478
                         UIEvents.RECORDING_TOGGLED,
462
                         { streamId });
479
                         { streamId });
463
                     sendEvent('recording.started');
480
                     sendEvent('recording.started');
464
-                }).catch(reason => {
465
-                    if (reason !== APP.UI.messageHandler.CANCEL)
466
-                        logger.error(reason);
467
-                    else
481
+                })
482
+                .catch(reason => {
483
+                    if (reason === APP.UI.messageHandler.CANCEL) {
468
                         sendEvent('recording.canceled');
484
                         sendEvent('recording.canceled');
485
+                    } else {
486
+                        logger.error(reason);
487
+                    }
469
                 });
488
                 });
470
-            else {
489
+            } else {
471
                 if (this.predefinedToken) {
490
                 if (this.predefinedToken) {
472
                     this.eventEmitter.emit(
491
                     this.eventEmitter.emit(
473
                         UIEvents.RECORDING_TOGGLED,
492
                         UIEvents.RECORDING_TOGGLED,
474
                         { token: this.predefinedToken });
493
                         { token: this.predefinedToken });
475
                     sendEvent('recording.started');
494
                     sendEvent('recording.started');
495
+
476
                     return;
496
                     return;
477
                 }
497
                 }
478
 
498
 
479
-                _requestRecordingToken().then((token) => {
499
+                _requestRecordingToken().then(token => {
480
                     this.eventEmitter.emit(
500
                     this.eventEmitter.emit(
481
                         UIEvents.RECORDING_TOGGLED,
501
                         UIEvents.RECORDING_TOGGLED,
482
                         { token });
502
                         { token });
483
                     sendEvent('recording.started');
503
                     sendEvent('recording.started');
484
-                }).catch(reason => {
485
-                    if (reason !== APP.UI.messageHandler.CANCEL)
486
-                        logger.error(reason);
487
-                    else
504
+                })
505
+                .catch(reason => {
506
+                    if (reason === APP.UI.messageHandler.CANCEL) {
488
                         sendEvent('recording.canceled');
507
                         sendEvent('recording.canceled');
508
+                    } else {
509
+                        logger.error(reason);
510
+                    }
489
                 });
511
                 });
490
             }
512
             }
491
             break;
513
             break;
521
      * or not
543
      * or not
522
      */
544
      */
523
     _setToolbarButtonToggled(isToggled) {
545
     _setToolbarButtonToggled(isToggled) {
524
-        $("#toolbar_button_record").toggleClass("toggled", isToggled);
546
+        $('#toolbar_button_record').toggleClass('toggled', isToggled);
525
     }
547
     }
526
 };
548
 };
527
 
549
 

+ 215
- 148
modules/UI/shared_video/SharedVideo.js View File

1
 /* global $, APP, YT, onPlayerReady, onPlayerStateChange, onPlayerError */
1
 /* global $, APP, YT, onPlayerReady, onPlayerStateChange, onPlayerError */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
2
+const logger = require('jitsi-meet-logger').getLogger(__filename);
3
 
3
 
4
 import UIUtil from '../util/UIUtil';
4
 import UIUtil from '../util/UIUtil';
5
 import UIEvents from '../../../service/UI/UIEvents';
5
 import UIEvents from '../../../service/UI/UIEvents';
6
 
6
 
7
-import VideoLayout from "../videolayout/VideoLayout";
7
+import VideoLayout from '../videolayout/VideoLayout';
8
 import LargeContainer from '../videolayout/LargeContainer';
8
 import LargeContainer from '../videolayout/LargeContainer';
9
 import Filmstrip from '../videolayout/Filmstrip';
9
 import Filmstrip from '../videolayout/Filmstrip';
10
 
10
 
17
 
17
 
18
 import SharedVideoThumb from './SharedVideoThumb';
18
 import SharedVideoThumb from './SharedVideoThumb';
19
 
19
 
20
-export const SHARED_VIDEO_CONTAINER_TYPE = "sharedvideo";
20
+export const SHARED_VIDEO_CONTAINER_TYPE = 'sharedvideo';
21
 
21
 
22
 /**
22
 /**
23
  * Example shared video link.
23
  * Example shared video link.
24
  * @type {string}
24
  * @type {string}
25
  */
25
  */
26
-const defaultSharedVideoLink = "https://www.youtube.com/watch?v=xNXN7CZk8X0";
26
+const defaultSharedVideoLink = 'https://www.youtube.com/watch?v=xNXN7CZk8X0';
27
 const updateInterval = 5000; // milliseconds
27
 const updateInterval = 5000; // milliseconds
28
 
28
 
29
 /**
29
 /**
36
  * Manager of shared video.
36
  * Manager of shared video.
37
  */
37
  */
38
 export default class SharedVideoManager {
38
 export default class SharedVideoManager {
39
-    constructor (emitter) {
39
+    /**
40
+     *
41
+     */
42
+    constructor(emitter) {
40
         this.emitter = emitter;
43
         this.emitter = emitter;
41
         this.isSharedVideoShown = false;
44
         this.isSharedVideoShown = false;
42
         this.isPlayerAPILoaded = false;
45
         this.isPlayerAPILoaded = false;
52
      * currently on.
55
      * currently on.
53
      */
56
      */
54
     isSharedVideoVolumeOn() {
57
     isSharedVideoVolumeOn() {
55
-        return (this.player
58
+        return this.player
56
                 && this.player.getPlayerState() === YT.PlayerState.PLAYING
59
                 && this.player.getPlayerState() === YT.PlayerState.PLAYING
57
                 && !this.player.isMuted()
60
                 && !this.player.isMuted()
58
-                && this.player.getVolume() > 0);
61
+                && this.player.getVolume() > 0;
59
     }
62
     }
60
 
63
 
61
     /**
64
     /**
70
      * Starts shared video by asking user for url, or if its already working
73
      * Starts shared video by asking user for url, or if its already working
71
      * asks whether the user wants to stop sharing the video.
74
      * asks whether the user wants to stop sharing the video.
72
      */
75
      */
73
-    toggleSharedVideo () {
74
-        if (dialog)
76
+    toggleSharedVideo() {
77
+        if (dialog) {
75
             return;
78
             return;
79
+        }
76
 
80
 
77
-        if(!this.isSharedVideoShown) {
81
+        if (!this.isSharedVideoShown) {
78
             requestVideoLink().then(
82
             requestVideoLink().then(
79
                     url => {
83
                     url => {
80
                         this.emitter.emit(
84
                         this.emitter.emit(
86
                         sendEvent('sharedvideo.canceled');
90
                         sendEvent('sharedvideo.canceled');
87
                     }
91
                     }
88
             );
92
             );
93
+
89
             return;
94
             return;
90
         }
95
         }
91
 
96
 
92
-        if(APP.conference.isLocalId(this.from)) {
97
+        if (APP.conference.isLocalId(this.from)) {
93
             showStopVideoPropmpt().then(
98
             showStopVideoPropmpt().then(
94
                 () => {
99
                 () => {
95
                     // make sure we stop updates for playing before we send stop
100
                     // make sure we stop updates for playing before we send stop
104
                         UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop');
109
                         UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop');
105
                     sendEvent('sharedvideo.stoped');
110
                     sendEvent('sharedvideo.stoped');
106
                 },
111
                 },
107
-                () => {});
112
+                () => {}); // eslint-disable-line no-empty-function
108
         } else {
113
         } else {
109
             dialog = APP.UI.messageHandler.openMessageDialog(
114
             dialog = APP.UI.messageHandler.openMessageDialog(
110
-                "dialog.shareVideoTitle",
111
-                "dialog.alreadySharedVideoMsg",
115
+                'dialog.shareVideoTitle',
116
+                'dialog.alreadySharedVideoMsg',
112
                 null,
117
                 null,
113
-                function () {
118
+                () => {
114
                     dialog = null;
119
                     dialog = null;
115
                 }
120
                 }
116
             );
121
             );
126
      * @param url the video url
131
      * @param url the video url
127
      * @param attributes
132
      * @param attributes
128
      */
133
      */
129
-    onSharedVideoStart (id, url, attributes) {
130
-        if (this.isSharedVideoShown)
134
+    onSharedVideoStart(id, url, attributes) {
135
+        if (this.isSharedVideoShown) {
131
             return;
136
             return;
137
+        }
132
 
138
 
133
         this.isSharedVideoShown = true;
139
         this.isSharedVideoShown = true;
134
 
140
 
140
 
146
 
141
         this.mutedWithUserInteraction = APP.conference.isLocalAudioMuted();
147
         this.mutedWithUserInteraction = APP.conference.isLocalAudioMuted();
142
 
148
 
143
-        //listen for local audio mute events
149
+        // listen for local audio mute events
144
         this.localAudioMutedListener = this.onLocalAudioMuted.bind(this);
150
         this.localAudioMutedListener = this.onLocalAudioMuted.bind(this);
145
         this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener);
151
         this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener);
146
 
152
 
147
         // This code loads the IFrame Player API code asynchronously.
153
         // This code loads the IFrame Player API code asynchronously.
148
-        var tag = document.createElement('script');
154
+        const tag = document.createElement('script');
155
+
156
+        tag.src = 'https://www.youtube.com/iframe_api';
157
+        const firstScriptTag = document.getElementsByTagName('script')[0];
149
 
158
 
150
-        tag.src = "https://www.youtube.com/iframe_api";
151
-        var firstScriptTag = document.getElementsByTagName('script')[0];
152
         firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
159
         firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
153
 
160
 
154
         // sometimes we receive errors like player not defined
161
         // sometimes we receive errors like player not defined
158
         // and will process any initial attributes if any
165
         // and will process any initial attributes if any
159
         this.initialAttributes = attributes;
166
         this.initialAttributes = attributes;
160
 
167
 
161
-        var self = this;
162
-        if(self.isPlayerAPILoaded)
168
+        const self = this;
169
+
170
+        if (self.isPlayerAPILoaded) {
163
             window.onYouTubeIframeAPIReady();
171
             window.onYouTubeIframeAPIReady();
164
-        else
172
+        } else {
165
             window.onYouTubeIframeAPIReady = function() {
173
             window.onYouTubeIframeAPIReady = function() {
166
                 self.isPlayerAPILoaded = true;
174
                 self.isPlayerAPILoaded = true;
167
-                let showControls = APP.conference.isLocalId(self.from) ? 1 : 0;
168
-                let p = new YT.Player('sharedVideoIFrame', {
175
+                const showControls
176
+                    = APP.conference.isLocalId(self.from) ? 1 : 0;
177
+                const p = new YT.Player('sharedVideoIFrame', {
169
                     height: '100%',
178
                     height: '100%',
170
                     width: '100%',
179
                     width: '100%',
171
                     videoId: self.url,
180
                     videoId: self.url,
174
                         'fs': '0',
183
                         'fs': '0',
175
                         'autoplay': 0,
184
                         'autoplay': 0,
176
                         'controls': showControls,
185
                         'controls': showControls,
177
-                        'rel' : 0
186
+                        'rel': 0
178
                     },
187
                     },
179
                     events: {
188
                     events: {
180
                         'onReady': onPlayerReady,
189
                         'onReady': onPlayerReady,
185
 
194
 
186
                 // add listener for volume changes
195
                 // add listener for volume changes
187
                 p.addEventListener(
196
                 p.addEventListener(
188
-                    "onVolumeChange", "onVolumeChange");
197
+                    'onVolumeChange', 'onVolumeChange');
189
 
198
 
190
-                if (APP.conference.isLocalId(self.from)){
191
-                    // adds progress listener that will be firing events
192
-                    // while we are paused and we change the progress of the
193
-                    // video (seeking forward or backward on the video)
199
+                if (APP.conference.isLocalId(self.from)) {
200
+                // adds progress listener that will be firing events
201
+                // while we are paused and we change the progress of the
202
+                // video (seeking forward or backward on the video)
194
                     p.addEventListener(
203
                     p.addEventListener(
195
-                        "onVideoProgress", "onVideoProgress");
204
+                        'onVideoProgress', 'onVideoProgress');
196
                 }
205
                 }
197
             };
206
             };
207
+        }
198
 
208
 
199
         /**
209
         /**
200
          * Indicates that a change in state has occurred for the shared video.
210
          * Indicates that a change in state has occurred for the shared video.
201
          * @param event the event notifying us of the change
211
          * @param event the event notifying us of the change
202
          */
212
          */
203
         window.onPlayerStateChange = function(event) {
213
         window.onPlayerStateChange = function(event) {
214
+            // eslint-disable-next-line eqeqeq
204
             if (event.data == YT.PlayerState.PLAYING) {
215
             if (event.data == YT.PlayerState.PLAYING) {
205
-
206
                 self.player = event.target;
216
                 self.player = event.target;
207
 
217
 
208
-                if(self.initialAttributes)
209
-                {
218
+                if (self.initialAttributes) {
210
                     // If a network update has occurred already now is the
219
                     // If a network update has occurred already now is the
211
                     // time to process it.
220
                     // time to process it.
212
                     self.processVideoUpdate(
221
                     self.processVideoUpdate(
216
                     self.initialAttributes = null;
225
                     self.initialAttributes = null;
217
                 }
226
                 }
218
                 self.smartAudioMute();
227
                 self.smartAudioMute();
228
+                // eslint-disable-next-line eqeqeq
219
             } else if (event.data == YT.PlayerState.PAUSED) {
229
             } else if (event.data == YT.PlayerState.PAUSED) {
220
                 self.smartAudioUnmute();
230
                 self.smartAudioUnmute();
221
                 sendEvent('sharedvideo.paused');
231
                 sendEvent('sharedvideo.paused');
222
             }
232
             }
233
+            // eslint-disable-next-line eqeqeq
223
             self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED);
234
             self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED);
224
         };
235
         };
225
 
236
 
227
          * Track player progress while paused.
238
          * Track player progress while paused.
228
          * @param event
239
          * @param event
229
          */
240
          */
230
-        window.onVideoProgress = function (event) {
231
-            let state = event.target.getPlayerState();
241
+        window.onVideoProgress = function(event) {
242
+            const state = event.target.getPlayerState();
243
+
244
+            // eslint-disable-next-line eqeqeq
232
             if (state == YT.PlayerState.PAUSED) {
245
             if (state == YT.PlayerState.PAUSED) {
233
                 self.fireSharedVideoEvent(true);
246
                 self.fireSharedVideoEvent(true);
234
             }
247
             }
238
          * Gets notified for volume state changed.
251
          * Gets notified for volume state changed.
239
          * @param event
252
          * @param event
240
          */
253
          */
241
-        window.onVolumeChange = function (event) {
254
+        window.onVolumeChange = function(event) {
242
             self.fireSharedVideoEvent();
255
             self.fireSharedVideoEvent();
243
 
256
 
244
             // let's check, if player is not muted lets mute locally
257
             // let's check, if player is not muted lets mute locally
245
-            if(event.data.volume > 0 && !event.data.muted) {
258
+            if (event.data.volume > 0 && !event.data.muted) {
246
                 self.smartAudioMute();
259
                 self.smartAudioMute();
247
-            }
248
-            else if (event.data.volume <=0 || event.data.muted) {
260
+            } else if (event.data.volume <= 0 || event.data.muted) {
249
                 self.smartAudioUnmute();
261
                 self.smartAudioUnmute();
250
             }
262
             }
251
             sendEvent('sharedvideo.volumechanged');
263
             sendEvent('sharedvideo.volumechanged');
252
         };
264
         };
253
 
265
 
254
         window.onPlayerReady = function(event) {
266
         window.onPlayerReady = function(event) {
255
-            let player = event.target;
267
+            const player = event.target;
268
+
256
             // do not relay on autoplay as it is not sending all of the events
269
             // do not relay on autoplay as it is not sending all of the events
257
             // in onPlayerStateChange
270
             // in onPlayerStateChange
271
+
258
             player.playVideo();
272
             player.playVideo();
259
 
273
 
260
-            let thumb = new SharedVideoThumb(
274
+            const thumb = new SharedVideoThumb(
261
                 self.url, SHARED_VIDEO_CONTAINER_TYPE, VideoLayout);
275
                 self.url, SHARED_VIDEO_CONTAINER_TYPE, VideoLayout);
276
+
262
             thumb.setDisplayName(player.getVideoData().title);
277
             thumb.setDisplayName(player.getVideoData().title);
263
             VideoLayout.addRemoteVideoContainer(self.url, thumb);
278
             VideoLayout.addRemoteVideoContainer(self.url, thumb);
264
 
279
 
265
-            let iframe = player.getIframe();
280
+            const iframe = player.getIframe();
281
+
282
+            // eslint-disable-next-line no-use-before-define
266
             self.sharedVideo = new SharedVideoContainer(
283
             self.sharedVideo = new SharedVideoContainer(
267
-                {url, iframe, player});
284
+                { url,
285
+                    iframe,
286
+                    player });
268
 
287
 
269
-            //prevents pausing participants not sharing the video
288
+            // prevents pausing participants not sharing the video
270
             // to pause the video
289
             // to pause the video
271
             if (!APP.conference.isLocalId(self.from)) {
290
             if (!APP.conference.isLocalId(self.from)) {
272
-                $("#sharedVideo").css("pointer-events","none");
291
+                $('#sharedVideo').css('pointer-events', 'none');
273
             }
292
             }
274
 
293
 
275
             VideoLayout.addLargeVideoContainer(
294
             VideoLayout.addLargeVideoContainer(
285
 
304
 
286
             // If we are sending the command and we are starting the player
305
             // If we are sending the command and we are starting the player
287
             // we need to continuously send the player current time position
306
             // we need to continuously send the player current time position
288
-            if(APP.conference.isLocalId(self.from)) {
307
+            if (APP.conference.isLocalId(self.from)) {
289
                 self.intervalId = setInterval(
308
                 self.intervalId = setInterval(
290
                     self.fireSharedVideoEvent.bind(self),
309
                     self.fireSharedVideoEvent.bind(self),
291
                     updateInterval);
310
                     updateInterval);
293
         };
312
         };
294
 
313
 
295
         window.onPlayerError = function(event) {
314
         window.onPlayerError = function(event) {
296
-            logger.error("Error in the player:", event.data);
315
+            logger.error('Error in the player:', event.data);
316
+
297
             // store the error player, so we can remove it
317
             // store the error player, so we can remove it
298
             self.errorInPlayer = event.target;
318
             self.errorInPlayer = event.target;
299
         };
319
         };
304
      * @param player the player to operate over
324
      * @param player the player to operate over
305
      * @param attributes the attributes with the player state we want
325
      * @param attributes the attributes with the player state we want
306
      */
326
      */
307
-    processVideoUpdate (player, attributes)
308
-    {
309
-        if(!attributes)
327
+    processVideoUpdate(player, attributes) {
328
+        if (!attributes) {
310
             return;
329
             return;
330
+        }
311
 
331
 
332
+        // eslint-disable-next-line eqeqeq
312
         if (attributes.state == 'playing') {
333
         if (attributes.state == 'playing') {
313
 
334
 
314
-            let isPlayerPaused
315
-                = (this.player.getPlayerState() === YT.PlayerState.PAUSED);
335
+            const isPlayerPaused
336
+                = this.player.getPlayerState() === YT.PlayerState.PAUSED;
316
 
337
 
317
             // If our player is currently paused force the seek.
338
             // If our player is currently paused force the seek.
318
             this.processTime(player, attributes, isPlayerPaused);
339
             this.processTime(player, attributes, isPlayerPaused);
319
 
340
 
320
             // Process mute.
341
             // Process mute.
321
-            let isAttrMuted = (attributes.muted === "true");
342
+            const isAttrMuted = attributes.muted === 'true';
343
+
322
             if (player.isMuted() !== isAttrMuted) {
344
             if (player.isMuted() !== isAttrMuted) {
323
                 this.smartPlayerMute(isAttrMuted, true);
345
                 this.smartPlayerMute(isAttrMuted, true);
324
             }
346
             }
326
             // Process volume
348
             // Process volume
327
             if (!isAttrMuted
349
             if (!isAttrMuted
328
                 && attributes.volume !== undefined
350
                 && attributes.volume !== undefined
351
+                // eslint-disable-next-line eqeqeq
329
                 && player.getVolume() != attributes.volume) {
352
                 && player.getVolume() != attributes.volume) {
330
 
353
 
331
                 player.setVolume(attributes.volume);
354
                 player.setVolume(attributes.volume);
332
-                logger.info("Player change of volume:" + attributes.volume);
355
+                logger.info(`Player change of volume:${attributes.volume}`);
333
                 this.showSharedVideoMutedPopup(false);
356
                 this.showSharedVideoMutedPopup(false);
334
             }
357
             }
335
 
358
 
336
-            if (isPlayerPaused)
359
+            if (isPlayerPaused) {
337
                 player.playVideo();
360
                 player.playVideo();
338
-
361
+            }
362
+            // eslint-disable-next-line eqeqeq
339
         } else if (attributes.state == 'pause') {
363
         } else if (attributes.state == 'pause') {
340
             // if its not paused, pause it
364
             // if its not paused, pause it
341
             player.pauseVideo();
365
             player.pauseVideo();
350
      * @param attributes the attributes with the player state we want
374
      * @param attributes the attributes with the player state we want
351
      * @param forceSeek whether seek should be forced
375
      * @param forceSeek whether seek should be forced
352
      */
376
      */
353
-    processTime (player, attributes, forceSeek)
354
-    {
355
-        if(forceSeek) {
356
-            logger.info("Player seekTo:", attributes.time);
377
+    processTime(player, attributes, forceSeek) {
378
+        if (forceSeek) {
379
+            logger.info('Player seekTo:', attributes.time);
357
             player.seekTo(attributes.time);
380
             player.seekTo(attributes.time);
381
+
358
             return;
382
             return;
359
         }
383
         }
360
 
384
 
361
         // check received time and current time
385
         // check received time and current time
362
-        let currentPosition = player.getCurrentTime();
363
-        let diff = Math.abs(attributes.time - currentPosition);
386
+        const currentPosition = player.getCurrentTime();
387
+        const diff = Math.abs(attributes.time - currentPosition);
364
 
388
 
365
         // if we drift more than the interval for checking
389
         // if we drift more than the interval for checking
366
         // sync, the interval is in milliseconds
390
         // sync, the interval is in milliseconds
367
-        if(diff > updateInterval/1000) {
368
-            logger.info("Player seekTo:", attributes.time,
369
-                " current time is:", currentPosition, " diff:", diff);
391
+        if (diff > updateInterval / 1000) {
392
+            logger.info('Player seekTo:', attributes.time,
393
+                ' current time is:', currentPosition, ' diff:', diff);
370
             player.seekTo(attributes.time);
394
             player.seekTo(attributes.time);
371
         }
395
         }
372
     }
396
     }
374
     /**
398
     /**
375
      * Checks current state of the player and fire an event with the values.
399
      * Checks current state of the player and fire an event with the values.
376
      */
400
      */
377
-    fireSharedVideoEvent(sendPauseEvent)
378
-    {
401
+    fireSharedVideoEvent(sendPauseEvent) {
379
         // ignore update checks if we are not the owner of the video
402
         // ignore update checks if we are not the owner of the video
380
         // or there is still no player defined or we are stopped
403
         // or there is still no player defined or we are stopped
381
         // (in a process of stopping)
404
         // (in a process of stopping)
382
-        if(!APP.conference.isLocalId(this.from) || !this.player
383
-            || !this.isSharedVideoShown)
405
+        if (!APP.conference.isLocalId(this.from) || !this.player
406
+            || !this.isSharedVideoShown) {
384
             return;
407
             return;
408
+        }
409
+
410
+        const state = this.player.getPlayerState();
385
 
411
 
386
-        let state = this.player.getPlayerState();
387
         // if its paused and haven't been pause - send paused
412
         // if its paused and haven't been pause - send paused
413
+
388
         if (state === YT.PlayerState.PAUSED && sendPauseEvent) {
414
         if (state === YT.PlayerState.PAUSED && sendPauseEvent) {
389
             this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
415
             this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
390
                 this.url, 'pause', this.player.getCurrentTime());
416
                 this.url, 'pause', this.player.getCurrentTime());
391
-        }
392
-        // if its playing and it was paused - send update with time
393
-        // if its playing and was playing just send update with time
394
-        else if (state === YT.PlayerState.PLAYING) {
417
+        } else if (state === YT.PlayerState.PLAYING) {
418
+            // if its playing and it was paused - send update with time
419
+            // if its playing and was playing just send update with time
395
             this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
420
             this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
396
                 this.url, 'playing',
421
                 this.url, 'playing',
397
                 this.player.getCurrentTime(),
422
                 this.player.getCurrentTime(),
407
      * @param url the video url
432
      * @param url the video url
408
      * @param attributes
433
      * @param attributes
409
      */
434
      */
410
-    onSharedVideoUpdate (id, url, attributes) {
435
+    onSharedVideoUpdate(id, url, attributes) {
411
         // if we are sending the event ignore
436
         // if we are sending the event ignore
412
-        if(APP.conference.isLocalId(this.from)) {
437
+        if (APP.conference.isLocalId(this.from)) {
413
             return;
438
             return;
414
         }
439
         }
415
 
440
 
416
-        if(!this.isSharedVideoShown) {
441
+        if (!this.isSharedVideoShown) {
417
             this.onSharedVideoStart(id, url, attributes);
442
             this.onSharedVideoStart(id, url, attributes);
443
+
418
             return;
444
             return;
419
         }
445
         }
420
 
446
 
421
-        if(!this.player)
447
+        // eslint-disable-next-line no-negated-condition
448
+        if (!this.player) {
422
             this.initialAttributes = attributes;
449
             this.initialAttributes = attributes;
423
-        else {
450
+        } else {
424
             this.processVideoUpdate(this.player, attributes);
451
             this.processVideoUpdate(this.player, attributes);
425
         }
452
         }
426
     }
453
     }
431
      * left and we want to remove video if the user sharing it left).
458
      * left and we want to remove video if the user sharing it left).
432
      * @param id the id of the sender of the command
459
      * @param id the id of the sender of the command
433
      */
460
      */
434
-    onSharedVideoStop (id, attributes) {
435
-        if (!this.isSharedVideoShown)
461
+    onSharedVideoStop(id, attributes) {
462
+        if (!this.isSharedVideoShown) {
436
             return;
463
             return;
464
+        }
437
 
465
 
438
-        if(this.from !== id)
466
+        if (this.from !== id) {
439
             return;
467
             return;
468
+        }
440
 
469
 
441
-        if(!this.player) {
470
+        if (!this.player) {
442
             // if there is no error in the player till now,
471
             // if there is no error in the player till now,
443
             // store the initial attributes
472
             // store the initial attributes
444
             if (!this.errorInPlayer) {
473
             if (!this.errorInPlayer) {
445
                 this.initialAttributes = attributes;
474
                 this.initialAttributes = attributes;
475
+
446
                 return;
476
                 return;
447
             }
477
             }
448
         }
478
         }
458
                 VideoLayout.removeLargeVideoContainer(
488
                 VideoLayout.removeLargeVideoContainer(
459
                     SHARED_VIDEO_CONTAINER_TYPE);
489
                     SHARED_VIDEO_CONTAINER_TYPE);
460
 
490
 
461
-                if(this.player) {
491
+                if (this.player) {
462
                     this.player.destroy();
492
                     this.player.destroy();
463
                     this.player = null;
493
                     this.player = null;
464
-                } // if there is an error in player, remove that instance
465
-                else if (this.errorInPlayer) {
494
+                } else if (this.errorInPlayer) {
495
+                    // if there is an error in player, remove that instance
466
                     this.errorInPlayer.destroy();
496
                     this.errorInPlayer.destroy();
467
                     this.errorInPlayer = null;
497
                     this.errorInPlayer = null;
468
                 }
498
                 }
469
                 this.smartAudioUnmute();
499
                 this.smartAudioUnmute();
500
+
470
                 // revert to original behavior (prevents pausing
501
                 // revert to original behavior (prevents pausing
471
                 // for participants not sharing the video to pause it)
502
                 // for participants not sharing the video to pause it)
472
-                $("#sharedVideo").css("pointer-events","auto");
503
+                $('#sharedVideo').css('pointer-events', 'auto');
473
 
504
 
474
                 this.emitter.emit(
505
                 this.emitter.emit(
475
                     UIEvents.UPDATE_SHARED_VIDEO, null, 'removed');
506
                     UIEvents.UPDATE_SHARED_VIDEO, null, 'removed');
488
      * @param {boolean} indicates if this mute was a result of user interaction,
519
      * @param {boolean} indicates if this mute was a result of user interaction,
489
      * i.e. pressing the mute button or it was programatically triggerred
520
      * i.e. pressing the mute button or it was programatically triggerred
490
      */
521
      */
491
-    onLocalAudioMuted (muted, userInteraction) {
492
-        if(!this.player)
522
+    onLocalAudioMuted(muted, userInteraction) {
523
+        if (!this.player) {
493
             return;
524
             return;
525
+        }
494
 
526
 
495
         if (muted) {
527
         if (muted) {
496
             this.mutedWithUserInteraction = userInteraction;
528
             this.mutedWithUserInteraction = userInteraction;
497
-        }
498
-        else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) {
529
+        } else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) {
499
             this.smartPlayerMute(true, false);
530
             this.smartPlayerMute(true, false);
531
+
500
             // Check if we need to update other participants
532
             // Check if we need to update other participants
501
             this.fireSharedVideoEvent();
533
             this.fireSharedVideoEvent();
502
         }
534
         }
512
         if (!this.player.isMuted() && mute) {
544
         if (!this.player.isMuted() && mute) {
513
             this.player.mute();
545
             this.player.mute();
514
 
546
 
515
-            if (isVideoUpdate)
547
+            if (isVideoUpdate) {
516
                 this.smartAudioUnmute();
548
                 this.smartAudioUnmute();
517
-        }
518
-        else if (this.player.isMuted() && !mute) {
549
+            }
550
+        } else if (this.player.isMuted() && !mute) {
519
             this.player.unMute();
551
             this.player.unMute();
520
-            if (isVideoUpdate)
552
+            if (isVideoUpdate) {
521
                 this.smartAudioMute();
553
                 this.smartAudioMute();
554
+            }
522
         }
555
         }
523
 
556
 
524
         this.showSharedVideoMutedPopup(mute);
557
         this.showSharedVideoMutedPopup(mute);
533
         if (APP.conference.isLocalAudioMuted()
566
         if (APP.conference.isLocalAudioMuted()
534
             && !this.mutedWithUserInteraction
567
             && !this.mutedWithUserInteraction
535
             && !this.isSharedVideoVolumeOn()) {
568
             && !this.isSharedVideoVolumeOn()) {
536
-            sendEvent("sharedvideo.audio.unmuted");
569
+            sendEvent('sharedvideo.audio.unmuted');
537
             logger.log('Shared video: audio unmuted');
570
             logger.log('Shared video: audio unmuted');
538
             this.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
571
             this.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
539
             this.showMicMutedPopup(false);
572
             this.showMicMutedPopup(false);
547
     smartAudioMute() {
580
     smartAudioMute() {
548
         if (!APP.conference.isLocalAudioMuted()
581
         if (!APP.conference.isLocalAudioMuted()
549
             && this.isSharedVideoVolumeOn()) {
582
             && this.isSharedVideoVolumeOn()) {
550
-            sendEvent("sharedvideo.audio.muted");
583
+            sendEvent('sharedvideo.audio.muted');
551
             logger.log('Shared video: audio muted');
584
             logger.log('Shared video: audio muted');
552
             this.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
585
             this.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
553
             this.showMicMutedPopup(true);
586
             this.showMicMutedPopup(true);
559
      * of automatic mute after a shared video has started.
592
      * of automatic mute after a shared video has started.
560
      * @param show boolean, show or hide the notification
593
      * @param show boolean, show or hide the notification
561
      */
594
      */
562
-    showMicMutedPopup (show) {
563
-        if(show)
595
+    showMicMutedPopup(show) {
596
+        if (show) {
564
             this.showSharedVideoMutedPopup(false);
597
             this.showSharedVideoMutedPopup(false);
598
+        }
565
 
599
 
566
         APP.UI.showCustomToolbarPopup(
600
         APP.UI.showCustomToolbarPopup(
567
             'microphone', 'micMutedPopup', show, 5000);
601
             'microphone', 'micMutedPopup', show, 5000);
573
      * mic.
607
      * mic.
574
      * @param show boolean, show or hide the notification
608
      * @param show boolean, show or hide the notification
575
      */
609
      */
576
-    showSharedVideoMutedPopup (show) {
577
-        if(show)
610
+    showSharedVideoMutedPopup(show) {
611
+        if (show) {
578
             this.showMicMutedPopup(false);
612
             this.showMicMutedPopup(false);
613
+        }
579
 
614
 
580
         APP.UI.showCustomToolbarPopup(
615
         APP.UI.showCustomToolbarPopup(
581
             'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
616
             'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
586
  * Container for shared video iframe.
621
  * Container for shared video iframe.
587
  */
622
  */
588
 class SharedVideoContainer extends LargeContainer {
623
 class SharedVideoContainer extends LargeContainer {
589
-
590
-    constructor ({url, iframe, player}) {
624
+    /**
625
+     *
626
+     */
627
+    constructor({ url, iframe, player }) {
591
         super();
628
         super();
592
 
629
 
593
         this.$iframe = $(iframe);
630
         this.$iframe = $(iframe);
595
         this.player = player;
632
         this.player = player;
596
     }
633
     }
597
 
634
 
598
-    show () {
599
-        let self = this;
635
+    /**
636
+     *
637
+     */
638
+    show() {
639
+        const self = this;
640
+
641
+
600
         return new Promise(resolve => {
642
         return new Promise(resolve => {
601
             this.$iframe.fadeIn(300, () => {
643
             this.$iframe.fadeIn(300, () => {
602
                 self.bodyBackground = document.body.style.background;
644
                 self.bodyBackground = document.body.style.background;
603
                 document.body.style.background = 'black';
645
                 document.body.style.background = 'black';
604
-                this.$iframe.css({opacity: 1});
646
+                this.$iframe.css({ opacity: 1 });
605
                 APP.store.dispatch(dockToolbox(true));
647
                 APP.store.dispatch(dockToolbox(true));
606
                 resolve();
648
                 resolve();
607
             });
649
             });
608
         });
650
         });
609
     }
651
     }
610
 
652
 
611
-    hide () {
612
-        let self = this;
653
+    /**
654
+     *
655
+     */
656
+    hide() {
657
+        const self = this;
658
+
613
         APP.store.dispatch(dockToolbox(false));
659
         APP.store.dispatch(dockToolbox(false));
660
+
614
         return new Promise(resolve => {
661
         return new Promise(resolve => {
615
             this.$iframe.fadeOut(300, () => {
662
             this.$iframe.fadeOut(300, () => {
616
                 document.body.style.background = self.bodyBackground;
663
                 document.body.style.background = self.bodyBackground;
617
-                this.$iframe.css({opacity: 0});
664
+                this.$iframe.css({ opacity: 0 });
618
                 resolve();
665
                 resolve();
619
             });
666
             });
620
         });
667
         });
621
     }
668
     }
622
 
669
 
623
-    onHoverIn () {
670
+    /**
671
+     *
672
+     */
673
+    onHoverIn() {
624
         APP.store.dispatch(showToolbox());
674
         APP.store.dispatch(showToolbox());
625
     }
675
     }
626
 
676
 
627
-    get id () {
677
+    /**
678
+     *
679
+     */
680
+    get id() {
628
         return this.url;
681
         return this.url;
629
     }
682
     }
630
 
683
 
631
-    resize (containerWidth, containerHeight) {
632
-        let height = containerHeight - Filmstrip.getFilmstripHeight();
684
+    /**
685
+     *
686
+     */
687
+    resize(containerWidth, containerHeight) {
688
+        const height = containerHeight - Filmstrip.getFilmstripHeight();
633
 
689
 
634
-        let width = containerWidth;
690
+        const width = containerWidth;
635
 
691
 
636
         this.$iframe.width(width).height(height);
692
         this.$iframe.width(width).height(height);
637
     }
693
     }
639
     /**
695
     /**
640
      * @return {boolean} do not switch on dominant speaker event if on stage.
696
      * @return {boolean} do not switch on dominant speaker event if on stage.
641
      */
697
      */
642
-    stayOnStage () {
698
+    stayOnStage() {
643
         return false;
699
         return false;
644
     }
700
     }
645
 }
701
 }
650
  * @returns {boolean}
706
  * @returns {boolean}
651
  */
707
  */
652
 function getYoutubeLink(url) {
708
 function getYoutubeLink(url) {
653
-    let p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;//jshint ignore:line
654
-    return (url.match(p)) ? RegExp.$1 : false;
709
+    const p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;// eslint-disable-line max-len
710
+
711
+
712
+    return url.match(p) ? RegExp.$1 : false;
655
 }
713
 }
656
 
714
 
657
 /**
715
 /**
658
  * Ask user if he want to close shared video.
716
  * Ask user if he want to close shared video.
659
  */
717
  */
660
 function showStopVideoPropmpt() {
718
 function showStopVideoPropmpt() {
661
-    return new Promise(function (resolve, reject) {
662
-        let submitFunction = function(e,v) {
719
+    return new Promise((resolve, reject) => {
720
+        const submitFunction = function(e, v) {
663
             if (v) {
721
             if (v) {
664
                 resolve();
722
                 resolve();
665
             } else {
723
             } else {
667
             }
725
             }
668
         };
726
         };
669
 
727
 
670
-        let closeFunction = function () {
728
+        const closeFunction = function() {
671
             dialog = null;
729
             dialog = null;
672
         };
730
         };
673
 
731
 
674
         dialog = APP.UI.messageHandler.openTwoButtonDialog({
732
         dialog = APP.UI.messageHandler.openTwoButtonDialog({
675
-            titleKey: "dialog.removeSharedVideoTitle",
676
-            msgKey: "dialog.removeSharedVideoMsg",
677
-            leftButtonKey: "dialog.Remove",
733
+            titleKey: 'dialog.removeSharedVideoTitle',
734
+            msgKey: 'dialog.removeSharedVideoMsg',
735
+            leftButtonKey: 'dialog.Remove',
678
             submitFunction,
736
             submitFunction,
679
             closeFunction
737
             closeFunction
680
         });
738
         });
686
  * Dialog validates client input to allow only youtube urls.
744
  * Dialog validates client input to allow only youtube urls.
687
  */
745
  */
688
 function requestVideoLink() {
746
 function requestVideoLink() {
689
-    let i18n = APP.translation;
690
-    const cancelButton = i18n.generateTranslationHTML("dialog.Cancel");
691
-    const shareButton = i18n.generateTranslationHTML("dialog.Share");
692
-    const backButton = i18n.generateTranslationHTML("dialog.Back");
747
+    const i18n = APP.translation;
748
+    const cancelButton = i18n.generateTranslationHTML('dialog.Cancel');
749
+    const shareButton = i18n.generateTranslationHTML('dialog.Share');
750
+    const backButton = i18n.generateTranslationHTML('dialog.Back');
693
     const linkError
751
     const linkError
694
-        = i18n.generateTranslationHTML("dialog.shareVideoLinkError");
752
+        = i18n.generateTranslationHTML('dialog.shareVideoLinkError');
695
 
753
 
696
-    return new Promise(function (resolve, reject) {
754
+    return new Promise((resolve, reject) => {
697
         dialog = APP.UI.messageHandler.openDialogWithStates({
755
         dialog = APP.UI.messageHandler.openDialogWithStates({
698
             state0: {
756
             state0: {
699
-                titleKey: "dialog.shareVideoTitle",
700
-                html:  `
701
-                    <input name="sharedVideoUrl" type="text"
702
-                           class="input-control"
703
-                           data-i18n="[placeholder]defaultLink"
757
+                titleKey: 'dialog.shareVideoTitle',
758
+                html: `
759
+                    <input name='sharedVideoUrl' type='text'
760
+                           class='input-control'
761
+                           data-i18n='[placeholder]defaultLink'
704
                            autofocus>`,
762
                            autofocus>`,
705
                 persistent: false,
763
                 persistent: false,
706
                 buttons: [
764
                 buttons: [
707
-                    {title: cancelButton, value: false},
708
-                    {title: shareButton, value: true}
765
+                    { title: cancelButton,
766
+                        value: false },
767
+                    { title: shareButton,
768
+                        value: true }
709
                 ],
769
                 ],
710
                 focus: ':input:first',
770
                 focus: ':input:first',
711
                 defaultButton: 1,
771
                 defaultButton: 1,
712
-                submit: function (e, v, m, f) {
772
+                submit(e, v, m, f) { // eslint-disable-line max-params
713
                     e.preventDefault();
773
                     e.preventDefault();
714
                     if (!v) {
774
                     if (!v) {
715
                         reject('cancelled');
775
                         reject('cancelled');
716
                         dialog.close();
776
                         dialog.close();
777
+
717
                         return;
778
                         return;
718
                     }
779
                     }
719
 
780
 
720
-                    let sharedVideoUrl = f.sharedVideoUrl;
781
+                    const sharedVideoUrl = f.sharedVideoUrl;
782
+
721
                     if (!sharedVideoUrl) {
783
                     if (!sharedVideoUrl) {
722
                         return;
784
                         return;
723
                     }
785
                     }
724
 
786
 
725
-                    let urlValue = encodeURI(UIUtil.escapeHtml(sharedVideoUrl));
726
-                    let yVideoId = getYoutubeLink(urlValue);
787
+                    const urlValue
788
+                        = encodeURI(UIUtil.escapeHtml(sharedVideoUrl));
789
+                    const yVideoId = getYoutubeLink(urlValue);
790
+
727
                     if (!yVideoId) {
791
                     if (!yVideoId) {
728
                         dialog.goToState('state1');
792
                         dialog.goToState('state1');
793
+
729
                         return false;
794
                         return false;
730
                     }
795
                     }
731
 
796
 
735
             },
800
             },
736
 
801
 
737
             state1: {
802
             state1: {
738
-                titleKey: "dialog.shareVideoTitle",
803
+                titleKey: 'dialog.shareVideoTitle',
739
                 html: linkError,
804
                 html: linkError,
740
                 persistent: false,
805
                 persistent: false,
741
                 buttons: [
806
                 buttons: [
742
-                    {title: cancelButton, value: false},
743
-                    {title: backButton, value: true}
807
+                    { title: cancelButton,
808
+                        value: false },
809
+                    { title: backButton,
810
+                        value: true }
744
                 ],
811
                 ],
745
                 focus: ':input:first',
812
                 focus: ':input:first',
746
                 defaultButton: 1,
813
                 defaultButton: 1,
747
-                submit: function (e, v) {
814
+                submit(e, v) {
748
                     e.preventDefault();
815
                     e.preventDefault();
749
                     if (v === 0) {
816
                     if (v === 0) {
750
                         reject();
817
                         reject();
755
                 }
822
                 }
756
             }
823
             }
757
         }, {
824
         }, {
758
-            close: function () {
825
+            close() {
759
                 dialog = null;
826
                 dialog = null;
760
             }
827
             }
761
         }, {
828
         }, {

+ 25
- 16
modules/UI/shared_video/SharedVideoThumb.js View File

1
 /* global $ */
1
 /* global $ */
2
 import SmallVideo from '../videolayout/SmallVideo';
2
 import SmallVideo from '../videolayout/SmallVideo';
3
 
3
 
4
-const logger = require("jitsi-meet-logger").getLogger(__filename);
4
+const logger = require('jitsi-meet-logger').getLogger(__filename);
5
 
5
 
6
-export default function SharedVideoThumb (url, videoType, VideoLayout)
7
-{
6
+/**
7
+ *
8
+ */
9
+export default function SharedVideoThumb(url, videoType, VideoLayout) {
8
     this.id = url;
10
     this.id = url;
9
 
11
 
10
     this.url = url;
12
     this.url = url;
11
     this.setVideoType(videoType);
13
     this.setVideoType(videoType);
12
-    this.videoSpanId = "sharedVideoContainer";
14
+    this.videoSpanId = 'sharedVideoContainer';
13
     this.container = this.createContainer(this.videoSpanId);
15
     this.container = this.createContainer(this.videoSpanId);
14
     this.$container = $(this.container);
16
     this.$container = $(this.container);
15
     this.container.onclick = this.videoClick.bind(this);
17
     this.container.onclick = this.videoClick.bind(this);
23
 /**
25
 /**
24
  * hide display name
26
  * hide display name
25
  */
27
  */
28
+// eslint-disable-next-line no-empty-function
29
+SharedVideoThumb.prototype.setDeviceAvailabilityIcons = function() {};
26
 
30
 
27
-SharedVideoThumb.prototype.setDeviceAvailabilityIcons = function () {};
31
+// eslint-disable-next-line no-empty-function
32
+SharedVideoThumb.prototype.avatarChanged = function() {};
28
 
33
 
29
-SharedVideoThumb.prototype.avatarChanged = function () {};
34
+SharedVideoThumb.prototype.createContainer = function(spanId) {
35
+    const container = document.createElement('span');
30
 
36
 
31
-SharedVideoThumb.prototype.createContainer = function (spanId) {
32
-    var container = document.createElement('span');
33
     container.id = spanId;
37
     container.id = spanId;
34
     container.className = 'videocontainer';
38
     container.className = 'videocontainer';
35
 
39
 
36
     // add the avatar
40
     // add the avatar
37
-    var avatar = document.createElement('img');
41
+    const avatar = document.createElement('img');
42
+
38
     avatar.className = 'sharedVideoAvatar';
43
     avatar.className = 'sharedVideoAvatar';
39
-    avatar.src = "https://img.youtube.com/vi/" + this.url + "/0.jpg";
44
+    avatar.src = `https://img.youtube.com/vi/${this.url}/0.jpg`;
40
     container.appendChild(avatar);
45
     container.appendChild(avatar);
41
 
46
 
42
     const displayNameContainer = document.createElement('div');
47
     const displayNameContainer = document.createElement('div');
48
+
43
     displayNameContainer.className = 'displayNameContainer';
49
     displayNameContainer.className = 'displayNameContainer';
44
     container.appendChild(displayNameContainer);
50
     container.appendChild(displayNameContainer);
45
 
51
 
46
-    var remotes = document.getElementById('filmstripRemoteVideosContainer');
52
+    const remotes = document.getElementById('filmstripRemoteVideosContainer');
53
+
54
+
47
     return remotes.appendChild(container);
55
     return remotes.appendChild(container);
48
 };
56
 };
49
 
57
 
50
 /**
58
 /**
51
  * The thumb click handler.
59
  * The thumb click handler.
52
  */
60
  */
53
-SharedVideoThumb.prototype.videoClick = function () {
61
+SharedVideoThumb.prototype.videoClick = function() {
54
     this.VideoLayout.handleVideoThumbClicked(this.url);
62
     this.VideoLayout.handleVideoThumbClicked(this.url);
55
 };
63
 };
56
 
64
 
57
 /**
65
 /**
58
  * Removes RemoteVideo from the page.
66
  * Removes RemoteVideo from the page.
59
  */
67
  */
60
-SharedVideoThumb.prototype.remove = function () {
61
-    logger.log("Remove shared video thumb", this.id);
68
+SharedVideoThumb.prototype.remove = function() {
69
+    logger.log('Remove shared video thumb', this.id);
62
 
70
 
63
     // Make sure that the large video is updated if are removing its
71
     // Make sure that the large video is updated if are removing its
64
     // corresponding small video.
72
     // corresponding small video.
75
  */
83
  */
76
 SharedVideoThumb.prototype.setDisplayName = function(displayName) {
84
 SharedVideoThumb.prototype.setDisplayName = function(displayName) {
77
     if (!this.container) {
85
     if (!this.container) {
78
-        logger.warn( "Unable to set displayName - " + this.videoSpanId +
79
-            " does not exist");
86
+        logger.warn(`Unable to set displayName - ${this.videoSpanId
87
+        } does not exist`);
88
+
80
         return;
89
         return;
81
     }
90
     }
82
 
91
 

+ 48
- 30
modules/UI/side_pannels/SideContainerToggler.js View File

1
 /* global $ */
1
 /* global $ */
2
-import UIEvents from "../../../service/UI/UIEvents";
2
+import UIEvents from '../../../service/UI/UIEvents';
3
 
3
 
4
 /**
4
 /**
5
  * Handles open and close of the extended toolbar side panel
5
  * Handles open and close of the extended toolbar side panel
19
         // We may not have a side toolbar container, for example, in
19
         // We may not have a side toolbar container, for example, in
20
         // filmstrip-only mode.
20
         // filmstrip-only mode.
21
         const sideToolbarContainer
21
         const sideToolbarContainer
22
-            = document.getElementById("sideToolbarContainer");
22
+            = document.getElementById('sideToolbarContainer');
23
 
23
 
24
-        if (!sideToolbarContainer)
24
+        if (!sideToolbarContainer) {
25
             return;
25
             return;
26
+        }
26
 
27
 
27
         // Adds a listener for the animationend event that would take care of
28
         // Adds a listener for the animationend event that would take care of
28
         // hiding all internal containers when the extendedToolbarPanel is
29
         // hiding all internal containers when the extendedToolbarPanel is
29
         // closed.
30
         // closed.
30
         sideToolbarContainer.addEventListener(
31
         sideToolbarContainer.addEventListener(
31
-            "animationend",
32
-            function(e) {
33
-                if (e.animationName === "slideOutExt")
34
-                    $("#sideToolbarContainer").children().each(function() {
35
-                        if ($(this).hasClass("show"))
32
+            'animationend',
33
+            e => {
34
+                if (e.animationName === 'slideOutExt') {
35
+                    $('#sideToolbarContainer').children()
36
+                    .each(function() {
37
+                        /* eslint-disable no-invalid-this */
38
+                        if ($(this).hasClass('show')) {
36
                             SideContainerToggler.hideInnerContainer($(this));
39
                             SideContainerToggler.hideInnerContainer($(this));
40
+                        }
41
+                        /* eslint-enable no-invalid-this */
37
                     });
42
                     });
43
+                }
38
             },
44
             },
39
             false);
45
             false);
40
     },
46
     },
46
      * toggle
52
      * toggle
47
      */
53
      */
48
     toggle(elementId) {
54
     toggle(elementId) {
49
-        let elementSelector = $(`#${elementId}`);
50
-        let isSelectorVisible = elementSelector.hasClass("show");
55
+        const elementSelector = $(`#${elementId}`);
56
+        const isSelectorVisible = elementSelector.hasClass('show');
51
 
57
 
52
         if (isSelectorVisible) {
58
         if (isSelectorVisible) {
53
             this.hide();
59
             this.hide();
54
-        }
55
-        else {
56
-            if (this.isVisible())
57
-                $("#sideToolbarContainer").children().each(function() {
58
-                    if ($(this).id !== elementId && $(this).hasClass("show"))
60
+        } else {
61
+            if (this.isVisible()) {
62
+                $('#sideToolbarContainer').children()
63
+                .each(function() {
64
+                    /* eslint-disable no-invalid-this */
65
+                    if ($(this).id !== elementId && $(this).hasClass('show')) {
59
                         SideContainerToggler.hideInnerContainer($(this));
66
                         SideContainerToggler.hideInnerContainer($(this));
67
+                    }
68
+                    /* eslint-enable no-invalid-this */
60
                 });
69
                 });
70
+            }
61
 
71
 
62
-            if (!this.isVisible())
72
+            if (!this.isVisible()) {
63
                 this.show();
73
                 this.show();
74
+            }
64
 
75
 
65
             this.showInnerContainer(elementSelector);
76
             this.showInnerContainer(elementSelector);
66
         }
77
         }
71
      * otherwise returns {false}.
82
      * otherwise returns {false}.
72
      */
83
      */
73
     isVisible() {
84
     isVisible() {
74
-        return $("#sideToolbarContainer").hasClass("slideInExt");
85
+        return $('#sideToolbarContainer').hasClass('slideInExt');
75
     },
86
     },
76
 
87
 
77
     /**
88
     /**
79
      * {false} otherwise.
90
      * {false} otherwise.
80
      */
91
      */
81
     isHovered() {
92
     isHovered() {
82
-        return $("#sideToolbarContainer:hover").length > 0;
93
+        return $('#sideToolbarContainer:hover').length > 0;
83
     },
94
     },
84
 
95
 
85
     /**
96
     /**
86
      * Hides the side toolbar panel with a slide out animation.
97
      * Hides the side toolbar panel with a slide out animation.
87
      */
98
      */
88
     hide() {
99
     hide() {
89
-        $("#sideToolbarContainer")
90
-            .removeClass("slideInExt").addClass("slideOutExt");
100
+        $('#sideToolbarContainer')
101
+            .removeClass('slideInExt')
102
+.addClass('slideOutExt');
91
     },
103
     },
92
 
104
 
93
     /**
105
     /**
94
      * Shows the side toolbar panel with a slide in animation.
106
      * Shows the side toolbar panel with a slide in animation.
95
      */
107
      */
96
     show() {
108
     show() {
97
-        if (!this.isVisible())
98
-            $("#sideToolbarContainer")
99
-                .removeClass("slideOutExt").addClass("slideInExt");
109
+        if (!this.isVisible()) {
110
+            $('#sideToolbarContainer')
111
+                .removeClass('slideOutExt')
112
+.addClass('slideInExt');
113
+        }
100
     },
114
     },
101
 
115
 
102
     /**
116
     /**
106
      * element to hide
120
      * element to hide
107
      */
121
      */
108
     hideInnerContainer(containerSelector) {
122
     hideInnerContainer(containerSelector) {
109
-        containerSelector.removeClass("show").addClass("hide");
123
+        containerSelector.removeClass('show').addClass('hide');
110
 
124
 
111
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
125
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
112
             containerSelector.attr('id'), false);
126
             containerSelector.attr('id'), false);
124
         // If we quickly show a container, while another one is animating
138
         // If we quickly show a container, while another one is animating
125
         // and animation never ends, so we do not really hide the first one and
139
         // and animation never ends, so we do not really hide the first one and
126
         // we end up with to shown panels
140
         // we end up with to shown panels
127
-        $("#sideToolbarContainer").children().each(function() {
128
-            if ($(this).hasClass("show"))
141
+        $('#sideToolbarContainer').children()
142
+        .each(function() {
143
+            /* eslint-disable no-invalid-this */
144
+            if ($(this).hasClass('show')) {
129
                 SideContainerToggler.hideInnerContainer($(this));
145
                 SideContainerToggler.hideInnerContainer($(this));
146
+            }
147
+            /* eslint-enable no-invalid-this */
130
         });
148
         });
131
 
149
 
132
-        containerSelector.removeClass("hide").addClass("show");
150
+        containerSelector.removeClass('hide').addClass('show');
133
 
151
 
134
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
152
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
135
             containerSelector.attr('id'), true);
153
             containerSelector.attr('id'), true);
138
     /**
156
     /**
139
      * TO FIX: do we need to resize the chat?
157
      * TO FIX: do we need to resize the chat?
140
      */
158
      */
141
-    resize () {
142
-        //let [width, height] = UIUtil.getSidePanelSize();
143
-        //Chat.resizeChat(width, height);
159
+    resize() {
160
+        // let [width, height] = UIUtil.getSidePanelSize();
161
+        // Chat.resizeChat(width, height);
144
     }
162
     }
145
 };
163
 };
146
 
164
 

+ 1
- 1
modules/UI/side_pannels/SidePanels.js View File

5
 import { isButtonEnabled } from '../../../react/features/toolbox';
5
 import { isButtonEnabled } from '../../../react/features/toolbox';
6
 
6
 
7
 const SidePanels = {
7
 const SidePanels = {
8
-    init (eventEmitter) {
8
+    init(eventEmitter) {
9
         // Initialize chat
9
         // Initialize chat
10
         if (isButtonEnabled('chat')) {
10
         if (isButtonEnabled('chat')) {
11
             Chat.init(eventEmitter);
11
             Chat.init(eventEmitter);

+ 120
- 89
modules/UI/side_pannels/chat/Chat.js View File

1
 /* global APP, $ */
1
 /* global APP, $ */
2
 
2
 
3
-import {processReplacements, linkify} from './Replacement';
3
+import { processReplacements, linkify } from './Replacement';
4
 import CommandsProcessor from './Commands';
4
 import CommandsProcessor from './Commands';
5
-import VideoLayout from "../../videolayout/VideoLayout";
5
+import VideoLayout from '../../videolayout/VideoLayout';
6
 
6
 
7
 import UIUtil from '../../util/UIUtil';
7
 import UIUtil from '../../util/UIUtil';
8
 import UIEvents from '../../../../service/UI/UIEvents';
8
 import UIEvents from '../../../../service/UI/UIEvents';
36
         </div>
36
         </div>
37
     </div>`;
37
     </div>`;
38
 
38
 
39
+/**
40
+ *
41
+ */
39
 function initHTML() {
42
 function initHTML() {
40
     $(`#${sidePanelsContainerId}`)
43
     $(`#${sidePanelsContainerId}`)
41
         .append(htmlStr);
44
         .append(htmlStr);
44
 /**
47
 /**
45
  * The container id, which is and the element id.
48
  * The container id, which is and the element id.
46
  */
49
  */
47
-var CHAT_CONTAINER_ID = "chat_container";
50
+const CHAT_CONTAINER_ID = 'chat_container';
48
 
51
 
49
 /**
52
 /**
50
  *  Updates visual notification, indicating that a message has arrived.
53
  *  Updates visual notification, indicating that a message has arrived.
66
             = document.getElementById('toolbar_button_chat');
69
             = document.getElementById('toolbar_button_chat');
67
         const leftIndent
70
         const leftIndent
68
             = (UIUtil.getTextWidth(chatButtonElement)
71
             = (UIUtil.getTextWidth(chatButtonElement)
69
-                    - UIUtil.getTextWidth(unreadMsgElement))
70
-                / 2;
72
+                - UIUtil.getTextWidth(unreadMsgElement)) / 2;
71
         const topIndent
73
         const topIndent
72
-            = (UIUtil.getTextHeight(chatButtonElement)
73
-                        - UIUtil.getTextHeight(unreadMsgElement))
74
-                    / 2
75
-                - 5;
74
+            = ((UIUtil.getTextHeight(chatButtonElement)
75
+                - UIUtil.getTextHeight(unreadMsgElement)) / 2) - 5;
76
 
76
 
77
         unreadMsgElement.setAttribute(
77
         unreadMsgElement.setAttribute(
78
                 'style',
78
                 'style',
79
-                'top:' + topIndent + '; left:' + leftIndent + ';');
80
-    }
81
-    else {
79
+                `top:${topIndent}; left:${leftIndent};`);
80
+    } else {
82
         unreadMsgSelector.html('');
81
         unreadMsgSelector.html('');
83
     }
82
     }
84
 
83
 
93
  * @returns {string}
92
  * @returns {string}
94
  */
93
  */
95
 function getCurrentTime(stamp) {
94
 function getCurrentTime(stamp) {
96
-    var now     = (stamp? new Date(stamp): new Date());
97
-    var hour    = now.getHours();
98
-    var minute  = now.getMinutes();
99
-    var second  = now.getSeconds();
100
-    if(hour.toString().length === 1) {
101
-        hour = '0'+hour;
95
+    const now = stamp ? new Date(stamp) : new Date();
96
+    let hour = now.getHours();
97
+    let minute = now.getMinutes();
98
+    let second = now.getSeconds();
99
+
100
+    if (hour.toString().length === 1) {
101
+        hour = `0${hour}`;
102
     }
102
     }
103
-    if(minute.toString().length === 1) {
104
-        minute = '0'+minute;
103
+    if (minute.toString().length === 1) {
104
+        minute = `0${minute}`;
105
     }
105
     }
106
-    if(second.toString().length === 1) {
107
-        second = '0'+second;
106
+    if (second.toString().length === 1) {
107
+        second = `0${second}`;
108
     }
108
     }
109
-    return hour+':'+minute+':'+second;
109
+
110
+    return `${hour}:${minute}:${second}`;
110
 }
111
 }
111
 
112
 
113
+/**
114
+ *
115
+ */
112
 function toggleSmileys() {
116
 function toggleSmileys() {
113
-    var smileys = $('#smileysContainer');
114
-    if(!smileys.is(':visible')) {
115
-        smileys.show("slide", { direction: "down", duration: 300});
117
+    const smileys = $('#smileysContainer'); // eslint-disable-line no-shadow
118
+
119
+    if (smileys.is(':visible')) {
120
+        smileys.hide('slide', { direction: 'down',
121
+            duration: 300 });
116
     } else {
122
     } else {
117
-        smileys.hide("slide", { direction: "down", duration: 300});
123
+        smileys.show('slide', { direction: 'down',
124
+            duration: 300 });
118
     }
125
     }
119
     $('#usermsg').focus();
126
     $('#usermsg').focus();
120
 }
127
 }
121
 
128
 
129
+/**
130
+ *
131
+ */
122
 function addClickFunction(smiley, number) {
132
 function addClickFunction(smiley, number) {
123
     smiley.onclick = function addSmileyToMessage() {
133
     smiley.onclick = function addSmileyToMessage() {
124
-        var usermsg = $('#usermsg');
125
-        var message = usermsg.val();
126
-        message += smileys['smiley' + number];
134
+        const usermsg = $('#usermsg');
135
+        let message = usermsg.val();
136
+
137
+        message += smileys[`smiley${number}`];
127
         usermsg.val(message);
138
         usermsg.val(message);
128
         usermsg.get(0).setSelectionRange(message.length, message.length);
139
         usermsg.get(0).setSelectionRange(message.length, message.length);
129
         toggleSmileys();
140
         toggleSmileys();
135
  * Adds the smileys container to the chat
146
  * Adds the smileys container to the chat
136
  */
147
  */
137
 function addSmileys() {
148
 function addSmileys() {
138
-    var smileysContainer = document.createElement('div');
149
+    const smileysContainer = document.createElement('div');
150
+
139
     smileysContainer.id = 'smileysContainer';
151
     smileysContainer.id = 'smileysContainer';
140
-    for(var i = 1; i <= 21; i++) {
141
-        var smileyContainer = document.createElement('div');
142
-        smileyContainer.id = 'smiley' + i;
152
+    for (let i = 1; i <= 21; i++) {
153
+        const smileyContainer = document.createElement('div');
154
+
155
+        smileyContainer.id = `smiley${i}`;
143
         smileyContainer.className = 'smileyContainer';
156
         smileyContainer.className = 'smileyContainer';
144
-        var smiley = document.createElement('img');
145
-        smiley.src = 'images/smileys/smiley' + i + '.svg';
146
-        smiley.className =  'smiley';
157
+        const smiley = document.createElement('img');
158
+
159
+        smiley.src = `images/smileys/smiley${i}.svg`;
160
+        smiley.className = 'smiley';
147
         addClickFunction(smiley, i);
161
         addClickFunction(smiley, i);
148
         smileyContainer.appendChild(smiley);
162
         smileyContainer.appendChild(smiley);
149
         smileysContainer.appendChild(smileyContainer);
163
         smileysContainer.appendChild(smileyContainer);
150
     }
164
     }
151
 
165
 
152
-    $("#chat_container").append(smileysContainer);
166
+    $('#chat_container').append(smileysContainer);
153
 }
167
 }
154
 
168
 
155
 /**
169
 /**
156
  * Resizes the chat conversation.
170
  * Resizes the chat conversation.
157
  */
171
  */
158
 function resizeChatConversation() {
172
 function resizeChatConversation() {
159
-    var msgareaHeight = $('#usermsg').outerHeight();
160
-    var chatspace = $('#' + CHAT_CONTAINER_ID);
161
-    var width = chatspace.width();
162
-    var chat = $('#chatconversation');
163
-    var smileys = $('#smileysarea');
173
+    const msgareaHeight = $('#usermsg').outerHeight();
174
+    const chatspace = $(`#${CHAT_CONTAINER_ID}`);
175
+    const width = chatspace.width();
176
+    const chat = $('#chatconversation');
177
+    const smileys = $('#smileysarea'); // eslint-disable-line no-shadow
164
 
178
 
165
     smileys.height(msgareaHeight);
179
     smileys.height(msgareaHeight);
166
-    $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
180
+    $('#smileys').css('bottom', (msgareaHeight - 26) / 2);
167
     $('#smileysContainer').css('bottom', msgareaHeight);
181
     $('#smileysContainer').css('bottom', msgareaHeight);
168
     chat.width(width - 10);
182
     chat.width(width - 10);
169
     chat.height(window.innerHeight - 15 - msgareaHeight);
183
     chat.height(window.innerHeight - 15 - msgareaHeight);
175
  *
189
  *
176
  * @param id {string} input id
190
  * @param id {string} input id
177
  */
191
  */
178
-function deferredFocus(id){
192
+function deferredFocus(id) {
179
     setTimeout(() => $(`#${id}`).focus(), 400);
193
     setTimeout(() => $(`#${id}`).focus(), 400);
180
 }
194
 }
195
+
181
 /**
196
 /**
182
  * Chat related user interface.
197
  * Chat related user interface.
183
  */
198
  */
184
-var Chat = {
199
+const Chat = {
185
     /**
200
     /**
186
      * Initializes chat related interface.
201
      * Initializes chat related interface.
187
      */
202
      */
188
-    init (eventEmitter) {
203
+    init(eventEmitter) {
189
         initHTML();
204
         initHTML();
190
         if (APP.conference.getLocalDisplayName()) {
205
         if (APP.conference.getLocalDisplayName()) {
191
             Chat.setChatConversationMode(true);
206
             Chat.setChatConversationMode(true);
192
         }
207
         }
193
 
208
 
194
-        $("#smileys").click(function() {
209
+        $('#smileys').click(() => {
195
             Chat.toggleSmileys();
210
             Chat.toggleSmileys();
196
         });
211
         });
197
 
212
 
198
-        $('#nickinput').keydown(function (event) {
213
+        $('#nickinput').keydown(function(event) {
199
             if (event.keyCode === 13) {
214
             if (event.keyCode === 13) {
200
                 event.preventDefault();
215
                 event.preventDefault();
201
-                let val = this.value;
202
-                this.value = '';
216
+                const val = this.value; // eslint-disable-line no-invalid-this
217
+
218
+                this.value = '';// eslint-disable-line no-invalid-this
203
                 eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
219
                 eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
204
                 deferredFocus('usermsg');
220
                 deferredFocus('usermsg');
205
             }
221
             }
206
         });
222
         });
207
 
223
 
208
-        var usermsg = $('#usermsg');
209
-        usermsg.keydown(function (event) {
224
+        const usermsg = $('#usermsg');
225
+
226
+        usermsg.keydown(function(event) {
210
             if (event.keyCode === 13) {
227
             if (event.keyCode === 13) {
211
                 event.preventDefault();
228
                 event.preventDefault();
212
-                var value = this.value;
229
+                const value = this.value; // eslint-disable-line no-invalid-this
230
+
213
                 usermsg.val('').trigger('autosize.resize');
231
                 usermsg.val('').trigger('autosize.resize');
214
-                this.focus();
215
-                var command = new CommandsProcessor(value, eventEmitter);
232
+                this.focus();// eslint-disable-line no-invalid-this
233
+                const command = new CommandsProcessor(value, eventEmitter);
234
+
216
                 if (command.isCommand()) {
235
                 if (command.isCommand()) {
217
                     command.processCommand();
236
                     command.processCommand();
218
                 } else {
237
                 } else {
219
-                    var message = UIUtil.escapeHtml(value);
238
+                    const message = UIUtil.escapeHtml(value);
239
+
220
                     eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
240
                     eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
221
                 }
241
                 }
222
             }
242
             }
223
         });
243
         });
224
 
244
 
225
-        var onTextAreaResize = function () {
245
+        const onTextAreaResize = function() {
226
             resizeChatConversation();
246
             resizeChatConversation();
227
             Chat.scrollChatToBottom();
247
             Chat.scrollChatToBottom();
228
         };
248
         };
229
-        usermsg.autosize({callback: onTextAreaResize});
249
+
250
+        usermsg.autosize({ callback: onTextAreaResize });
230
 
251
 
231
         eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
252
         eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
232
-            function(containerId, isVisible) {
233
-                if (containerId !== CHAT_CONTAINER_ID || !isVisible)
253
+            (containerId, isVisible) => {
254
+                if (containerId !== CHAT_CONTAINER_ID || !isVisible) {
234
                     return;
255
                     return;
256
+                }
235
 
257
 
236
                 unreadMessages = 0;
258
                 unreadMessages = 0;
237
                 updateVisualNotification();
259
                 updateVisualNotification();
257
     /**
279
     /**
258
      * Appends the given message to the chat conversation.
280
      * Appends the given message to the chat conversation.
259
      */
281
      */
260
-    updateChatConversation (id, displayName, message, stamp) {
261
-        var divClassName = '';
282
+    // eslint-disable-next-line max-params
283
+    updateChatConversation(id, displayName, message, stamp) {
284
+        let divClassName = '';
262
 
285
 
263
         if (APP.conference.isLocalId(id)) {
286
         if (APP.conference.isLocalId(id)) {
264
-            divClassName = "localuser";
287
+            divClassName = 'localuser';
265
         } else {
288
         } else {
266
-            divClassName = "remoteuser";
289
+            divClassName = 'remoteuser';
267
 
290
 
268
             if (!Chat.isVisible()) {
291
             if (!Chat.isVisible()) {
269
                 unreadMessages++;
292
                 unreadMessages++;
275
         // replace links and smileys
298
         // replace links and smileys
276
         // Strophe already escapes special symbols on sending,
299
         // Strophe already escapes special symbols on sending,
277
         // so we escape here only tags to avoid double &amp;
300
         // so we escape here only tags to avoid double &amp;
278
-        var escMessage = message.replace(/</g, '&lt;').
279
-            replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
280
-        var escDisplayName = UIUtil.escapeHtml(displayName);
301
+        const escMessage = message.replace(/</g, '&lt;')
302
+            .replace(/>/g, '&gt;')
303
+.replace(/\n/g, '<br/>');
304
+        const escDisplayName = UIUtil.escapeHtml(displayName);
305
+
306
+        // eslint-disable-next-line no-param-reassign
281
         message = processReplacements(escMessage);
307
         message = processReplacements(escMessage);
282
 
308
 
283
-        var messageContainer =
284
-            '<div class="chatmessage">'+
285
-                '<img src="images/chatArrow.svg" class="chatArrow">' +
286
-                '<div class="username ' + divClassName +'">' + escDisplayName +
287
-                '</div>' + '<div class="timestamp">' + getCurrentTime(stamp) +
288
-                '</div>' + '<div class="usermessage">' + message + '</div>' +
289
-            '</div>';
309
+        const messageContainer
310
+            = `${'<div class="chatmessage">'
311
+                + '<img src="images/chatArrow.svg" class="chatArrow">'
312
+                + '<div class="username '}${divClassName}">${escDisplayName
313
+            }</div><div class="timestamp">${getCurrentTime(stamp)
314
+            }</div><div class="usermessage">${message}</div>`
315
+            + '</div>';
290
 
316
 
291
         $('#chatconversation').append(messageContainer);
317
         $('#chatconversation').append(messageContainer);
292
         $('#chatconversation').animate(
318
         $('#chatconversation').animate(
293
-                { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
319
+                { scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
294
     },
320
     },
295
 
321
 
296
     /**
322
     /**
298
      * @param errorMessage the received error message.
324
      * @param errorMessage the received error message.
299
      * @param originalText the original message.
325
      * @param originalText the original message.
300
      */
326
      */
301
-    chatAddError (errorMessage, originalText) {
327
+    chatAddError(errorMessage, originalText) {
328
+        // eslint-disable-next-line no-param-reassign
302
         errorMessage = UIUtil.escapeHtml(errorMessage);
329
         errorMessage = UIUtil.escapeHtml(errorMessage);
330
+        // eslint-disable-next-line no-param-reassign
303
         originalText = UIUtil.escapeHtml(originalText);
331
         originalText = UIUtil.escapeHtml(originalText);
304
 
332
 
305
         $('#chatconversation').append(
333
         $('#chatconversation').append(
306
-            '<div class="errorMessage"><b>Error: </b>' + 'Your message' +
307
-            (originalText? (` "${originalText}"`) : "") +
308
-            ' was not sent.' +
309
-            (errorMessage? (' Reason: ' + errorMessage) : '') +  '</div>');
334
+            `${'<div class="errorMessage"><b>Error: </b>Your message'}${
335
+                originalText ? ` "${originalText}"` : ''
336
+            } was not sent.${
337
+                errorMessage ? ` Reason: ${errorMessage}` : ''}</div>`);
310
         $('#chatconversation').animate(
338
         $('#chatconversation').animate(
311
-            { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
339
+            { scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
312
     },
340
     },
313
 
341
 
314
     /**
342
     /**
315
      * Sets the subject to the UI
343
      * Sets the subject to the UI
316
      * @param subject the subject
344
      * @param subject the subject
317
      */
345
      */
318
-    setSubject (subject) {
346
+    setSubject(subject) {
319
         if (subject) {
347
         if (subject) {
348
+            // eslint-disable-next-line no-param-reassign
320
             subject = subject.trim();
349
             subject = subject.trim();
321
         }
350
         }
322
 
351
 
332
      * @param {boolean} isConversationMode if chat should be in
361
      * @param {boolean} isConversationMode if chat should be in
333
      * conversation mode or not.
362
      * conversation mode or not.
334
      */
363
      */
335
-    setChatConversationMode (isConversationMode) {
336
-        $('#' + CHAT_CONTAINER_ID)
364
+    setChatConversationMode(isConversationMode) {
365
+        $(`#${CHAT_CONTAINER_ID}`)
337
             .toggleClass('is-conversation-mode', isConversationMode);
366
             .toggleClass('is-conversation-mode', isConversationMode);
338
     },
367
     },
339
 
368
 
340
     /**
369
     /**
341
      * Resizes the chat area.
370
      * Resizes the chat area.
342
      */
371
      */
343
-    resizeChat (width, height) {
344
-        $('#' + CHAT_CONTAINER_ID).width(width).height(height);
372
+    resizeChat(width, height) {
373
+        $(`#${CHAT_CONTAINER_ID}`).width(width)
374
+.height(height);
345
 
375
 
346
         resizeChatConversation();
376
         resizeChatConversation();
347
     },
377
     },
349
     /**
379
     /**
350
      * Indicates if the chat is currently visible.
380
      * Indicates if the chat is currently visible.
351
      */
381
      */
352
-    isVisible () {
382
+    isVisible() {
353
         return UIUtil.isVisible(
383
         return UIUtil.isVisible(
354
             document.getElementById(CHAT_CONTAINER_ID));
384
             document.getElementById(CHAT_CONTAINER_ID));
355
     },
385
     },
386
+
356
     /**
387
     /**
357
      * Shows and hides the window with the smileys
388
      * Shows and hides the window with the smileys
358
      */
389
      */
361
     /**
392
     /**
362
      * Scrolls chat to the bottom.
393
      * Scrolls chat to the bottom.
363
      */
394
      */
364
-    scrollChatToBottom () {
395
+    scrollChatToBottom() {
365
         setTimeout(
396
         setTimeout(
366
             () => {
397
             () => {
367
                 const chatconversation = $('#chatconversation');
398
                 const chatconversation = $('#chatconversation');

+ 16
- 10
modules/UI/side_pannels/chat/Commands.js View File

7
  * @type {{String: function}}
7
  * @type {{String: function}}
8
  */
8
  */
9
 const commands = {
9
 const commands = {
10
-    "topic" : processTopic
10
+    'topic': processTopic
11
 };
11
 };
12
 
12
 
13
 /**
13
 /**
16
  * @returns {string} the command
16
  * @returns {string} the command
17
  */
17
  */
18
 function getCommand(message) {
18
 function getCommand(message) {
19
-    if(message) {
20
-        for(var command in commands) {
21
-            if(message.indexOf("/" + command) === 0)
19
+    if (message) {
20
+        for (const command in commands) {
21
+            if (message.indexOf(`/${command}`) === 0) {
22
                 return command;
22
                 return command;
23
+            }
23
         }
24
         }
24
     }
25
     }
25
-    return "";
26
+
27
+    return '';
26
 }
28
 }
27
 
29
 
28
 /**
30
 /**
30
  * @param commandArguments the arguments of the topic command.
32
  * @param commandArguments the arguments of the topic command.
31
  */
33
  */
32
 function processTopic(commandArguments, emitter) {
34
 function processTopic(commandArguments, emitter) {
33
-    var topic = UIUtil.escapeHtml(commandArguments);
35
+    const topic = UIUtil.escapeHtml(commandArguments);
36
+
34
     emitter.emit(UIEvents.SUBJECT_CHANGED, topic);
37
     emitter.emit(UIEvents.SUBJECT_CHANGED, topic);
35
 }
38
 }
36
 
39
 
41
  * @constructor
44
  * @constructor
42
  */
45
  */
43
 function CommandsProcessor(message, emitter) {
46
 function CommandsProcessor(message, emitter) {
44
-    var command = getCommand(message);
47
+    const command = getCommand(message);
45
 
48
 
46
     this.emitter = emitter;
49
     this.emitter = emitter;
47
 
50
 
54
     };
57
     };
55
 
58
 
56
 
59
 
57
-    var messageArgument = message.substr(command.length + 2);
60
+    const messageArgument = message.substr(command.length + 2);
58
 
61
 
59
     /**
62
     /**
60
      * Returns the arguments of the command.
63
      * Returns the arguments of the command.
70
  * @returns {boolean}
73
  * @returns {boolean}
71
  */
74
  */
72
 CommandsProcessor.prototype.isCommand = function() {
75
 CommandsProcessor.prototype.isCommand = function() {
73
-    if (this.getCommand())
76
+    if (this.getCommand()) {
74
         return true;
77
         return true;
78
+    }
79
+
75
     return false;
80
     return false;
76
 };
81
 };
77
 
82
 
79
  * Processes the command.
84
  * Processes the command.
80
  */
85
  */
81
 CommandsProcessor.prototype.processCommand = function() {
86
 CommandsProcessor.prototype.processCommand = function() {
82
-    if(!this.isCommand())
87
+    if (!this.isCommand()) {
83
         return;
88
         return;
89
+    }
84
 
90
 
85
     commands[this.getCommand()](this.getArgument(), this.emitter);
91
     commands[this.getCommand()](this.getArgument(), this.emitter);
86
 };
92
 };

+ 20
- 21
modules/UI/side_pannels/chat/Replacement.js View File

1
-/* jshint -W101 */
2
 import { regexes } from './smileys';
1
 import { regexes } from './smileys';
3
 
2
 
4
 /**
3
 /**
5
  * Processes links and smileys in "body"
4
  * Processes links and smileys in "body"
6
  */
5
  */
7
 export function processReplacements(body) {
6
 export function processReplacements(body) {
8
-    //make links clickable
9
-    body = linkify(body);
10
-
11
-    //add smileys
12
-    body = smilify(body);
13
-
14
-    return body;
7
+    // make links clickable + add smileys
8
+    return smilify(linkify(body));
15
 }
9
 }
16
 
10
 
17
 /**
11
 /**
19
  * with their <a href=""></a>
13
  * with their <a href=""></a>
20
  */
14
  */
21
 export function linkify(inputText) {
15
 export function linkify(inputText) {
22
-    var replacedText, replacePattern1, replacePattern2, replacePattern3;
16
+    let replacedText;
17
+
18
+    /* eslint-disable no-useless-escape, max-len */
23
 
19
 
24
-    /* eslint-disable no-useless-escape */
20
+    // URLs starting with http://, https://, or ftp://
21
+    const replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
25
 
22
 
26
-    //URLs starting with http://, https://, or ftp://
27
-    replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
28
     replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
23
     replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
29
 
24
 
30
-    //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
31
-    replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
25
+    // URLs starting with "www." (without // before it, or it'd re-link the ones done above).
26
+    const replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
27
+
32
     replacedText = replacedText.replace(replacePattern2, '$1<a href="https://$2" target="_blank" rel="noopener noreferrer">$2</a>');
28
     replacedText = replacedText.replace(replacePattern2, '$1<a href="https://$2" target="_blank" rel="noopener noreferrer">$2</a>');
33
 
29
 
34
-    //Change email addresses to mailto: links.
35
-    replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
30
+    // Change email addresses to mailto: links.
31
+    const replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
32
+
36
     replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
33
     replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
37
 
34
 
38
     /* eslint-enable no-useless-escape */
35
     /* eslint-enable no-useless-escape */
44
  * Replaces common smiley strings with images
41
  * Replaces common smiley strings with images
45
  */
42
  */
46
 function smilify(body) {
43
 function smilify(body) {
47
-    if(!body) {
44
+    if (!body) {
48
         return body;
45
         return body;
49
     }
46
     }
50
 
47
 
51
-    for(var smiley in regexes) {
52
-        if(regexes.hasOwnProperty(smiley)) {
53
-            body = body.replace(regexes[smiley],
54
-                    '<img class="smiley" src="images/smileys/' + smiley + '.svg">');
48
+    let formattedBody = body;
49
+
50
+    for (const smiley in regexes) {
51
+        if (regexes.hasOwnProperty(smiley)) {
52
+            formattedBody = formattedBody.replace(regexes[smiley],
53
+                `<img class="smiley" src="images/smileys/${smiley}.svg">`);
55
         }
54
         }
56
     }
55
     }
57
 
56
 

+ 21
- 21
modules/UI/side_pannels/chat/smileys.js View File

1
 export const smileys = {
1
 export const smileys = {
2
-    smiley1: ":)",
3
-    smiley2: ":(",
4
-    smiley3: ":D",
5
-    smiley4: "(y)",
6
-    smiley5: " :P",
7
-    smiley6: "(wave)",
8
-    smiley7: "(blush)",
9
-    smiley8: "(chuckle)",
10
-    smiley9: "(shocked)",
11
-    smiley10: ":*",
12
-    smiley11: "(n)",
13
-    smiley12: "(search)",
14
-    smiley13: " <3",
15
-    smiley14: "(oops)",
16
-    smiley15: "(angry)",
17
-    smiley16: "(angel)",
18
-    smiley17: "(sick)",
19
-    smiley18: ";(",
20
-    smiley19: "(bomb)",
21
-    smiley20: "(clap)",
22
-    smiley21: " ;)"
2
+    smiley1: ':)',
3
+    smiley2: ':(',
4
+    smiley3: ':D',
5
+    smiley4: '(y)',
6
+    smiley5: ' :P',
7
+    smiley6: '(wave)',
8
+    smiley7: '(blush)',
9
+    smiley8: '(chuckle)',
10
+    smiley9: '(shocked)',
11
+    smiley10: ':*',
12
+    smiley11: '(n)',
13
+    smiley12: '(search)',
14
+    smiley13: ' <3',
15
+    smiley14: '(oops)',
16
+    smiley15: '(angry)',
17
+    smiley16: '(angel)',
18
+    smiley17: '(sick)',
19
+    smiley18: ';(',
20
+    smiley19: '(bomb)',
21
+    smiley20: '(clap)',
22
+    smiley21: ' ;)'
23
 };
23
 };
24
 
24
 
25
 export const regexes = {
25
 export const regexes = {

+ 3
- 5
modules/UI/side_pannels/contactlist/ContactListView.js View File

19
  * the term "contact" is not used elsewhere. Normally people in the conference
19
  * the term "contact" is not used elsewhere. Normally people in the conference
20
  * are internally refered to as "participants" or externally as "members".
20
  * are internally refered to as "participants" or externally as "members".
21
  */
21
  */
22
-var ContactListView = {
22
+const ContactListView = {
23
     /**
23
     /**
24
      * Creates and appends the contact list to the side panel.
24
      * Creates and appends the contact list to the side panel.
25
      *
25
      *
33
 
33
 
34
         $('#sideToolbarContainer').append(contactListPanelContainer);
34
         $('#sideToolbarContainer').append(contactListPanelContainer);
35
 
35
 
36
-        /* jshint ignore:start */
37
         ReactDOM.render(
36
         ReactDOM.render(
38
             <Provider store = { APP.store }>
37
             <Provider store = { APP.store }>
39
                 <I18nextProvider i18n = { i18next }>
38
                 <I18nextProvider i18n = { i18next }>
42
             </Provider>,
41
             </Provider>,
43
             contactListPanelContainer
42
             contactListPanelContainer
44
         );
43
         );
45
-        /* jshint ignore:end */
46
     },
44
     },
47
 
45
 
48
     /**
46
     /**
50
      *
48
      *
51
      * @return {boolean) true if the contact list is currently visible.
49
      * @return {boolean) true if the contact list is currently visible.
52
      */
50
      */
53
-    isVisible () {
54
-        return UIUtil.isVisible(document.getElementById("contactlist"));
51
+    isVisible() {
52
+        return UIUtil.isVisible(document.getElementById('contactlist'));
55
     }
53
     }
56
 };
54
 };
57
 
55
 

+ 73
- 53
modules/UI/side_pannels/profile/Profile.js View File

1
 /* global $, APP */
1
 /* global $, APP */
2
-import UIUtil from "../../util/UIUtil";
3
-import UIEvents from "../../../../service/UI/UIEvents";
2
+import UIUtil from '../../util/UIUtil';
3
+import UIEvents from '../../../../service/UI/UIEvents';
4
 import Settings from '../../../settings/Settings';
4
 import Settings from '../../../settings/Settings';
5
 
5
 
6
 import { sendEvent } from '../../../../react/features/analytics';
6
 import { sendEvent } from '../../../../react/features/analytics';
7
 
7
 
8
 const sidePanelsContainerId = 'sideToolbarContainer';
8
 const sidePanelsContainerId = 'sideToolbarContainer';
9
 const htmlStr = `
9
 const htmlStr = `
10
-    <div id="profile_container" class="sideToolbarContainer__inner">
11
-        <div class="title" data-i18n="profile.title"></div>
12
-        <div class="sideToolbarBlock first">
13
-            <label class="first" data-i18n="profile.setDisplayNameLabel">
10
+    <div id='profile_container' class='sideToolbarContainer__inner'>
11
+        <div class='title' data-i18n='profile.title'></div>
12
+        <div class='sideToolbarBlock first'>
13
+            <label class='first' data-i18n='profile.setDisplayNameLabel'>
14
             </label>
14
             </label>
15
-            <input class="input-control" type="text" id="setDisplayName"
16
-                data-i18n="[placeholder]settings.name">
15
+            <input class='input-control' type='text' id='setDisplayName'
16
+                data-i18n='[placeholder]settings.name'>
17
         </div>
17
         </div>
18
-        <div class="sideToolbarBlock">
19
-            <label data-i18n="profile.setEmailLabel"></label>
20
-            <input id="setEmail" type="text" class="input-control"
21
-                data-i18n="[placeholder]profile.setEmailInput">
18
+        <div class='sideToolbarBlock'>
19
+            <label data-i18n='profile.setEmailLabel'></label>
20
+            <input id='setEmail' type='text' class='input-control'
21
+                data-i18n='[placeholder]profile.setEmailInput'>
22
         </div>
22
         </div>
23
-        <div id="profile_auth_container"
24
-             class="sideToolbarBlock auth_container">
25
-            <p data-i18n="toolbar.authenticate"></p>
23
+        <div id='profile_auth_container'
24
+             class='sideToolbarBlock auth_container'>
25
+            <p data-i18n='toolbar.authenticate'></p>
26
             <ul>
26
             <ul>
27
-                <li id="profile_auth_identity"></li>
28
-                <li id="profile_button_login">
29
-                    <a class="authButton" data-i18n="toolbar.login"></a>
27
+                <li id='profile_auth_identity'></li>
28
+                <li id='profile_button_login'>
29
+                    <a class='authButton' data-i18n='toolbar.login'></a>
30
                 </li>
30
                 </li>
31
-                <li id="profile_button_logout">
32
-                    <a class="authButton" data-i18n="toolbar.logout"></a>
31
+                <li id='profile_button_logout'>
32
+                    <a class='authButton' data-i18n='toolbar.logout'></a>
33
                 </li>
33
                 </li>
34
             </ul>
34
             </ul>
35
         </div>
35
         </div>
36
     </div>`;
36
     </div>`;
37
 
37
 
38
+/**
39
+ *
40
+ */
38
 function initHTML() {
41
 function initHTML() {
39
     $(`#${sidePanelsContainerId}`)
42
     $(`#${sidePanelsContainerId}`)
40
         .append(htmlStr);
43
         .append(htmlStr);
44
+
41
     // make sure we translate the panel, as adding it can be after i18n
45
     // make sure we translate the panel, as adding it can be after i18n
42
     // library had initialized and translated already present html
46
     // library had initialized and translated already present html
43
     APP.translation.translateElement($(`#${sidePanelsContainerId}`));
47
     APP.translation.translateElement($(`#${sidePanelsContainerId}`));
44
 }
48
 }
45
 
49
 
46
 export default {
50
 export default {
47
-    init (emitter) {
51
+    init(emitter) {
48
         initHTML();
52
         initHTML();
49
-        // DISPLAY NAME
50
-        function updateDisplayName () {
53
+
54
+        /**
55
+         * Updates display name.
56
+         *
57
+         * @returns {void}
58
+         */
59
+        function updateDisplayName() {
51
             emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
60
             emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
52
         }
61
         }
53
 
62
 
54
         $('#setDisplayName')
63
         $('#setDisplayName')
55
             .val(Settings.getDisplayName())
64
             .val(Settings.getDisplayName())
56
-            .keyup(function (event) {
65
+            .keyup(event => {
57
                 if (event.keyCode === 13) { // enter
66
                 if (event.keyCode === 13) { // enter
58
                     updateDisplayName();
67
                     updateDisplayName();
59
                 }
68
                 }
60
             })
69
             })
61
             .focusout(updateDisplayName);
70
             .focusout(updateDisplayName);
62
 
71
 
63
-
64
-        // EMAIL
65
-        function updateEmail () {
72
+        /**
73
+         * Updates the email.
74
+         *
75
+         * @returns {void}
76
+         */
77
+        function updateEmail() {
66
             emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
78
             emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
67
         }
79
         }
68
 
80
 
69
         $('#setEmail')
81
         $('#setEmail')
70
             .val(Settings.getEmail())
82
             .val(Settings.getEmail())
71
-            .keyup(function (event) {
83
+            .keyup(event => {
72
                 if (event.keyCode === 13) { // enter
84
                 if (event.keyCode === 13) { // enter
73
                     updateEmail();
85
                     updateEmail();
74
                 }
86
                 }
75
-            }).focusout(updateEmail);
87
+            })
88
+            .focusout(updateEmail);
76
 
89
 
77
-        // LOGIN
78
-        function loginClicked () {
90
+        /**
91
+         *
92
+         */
93
+        function loginClicked() {
79
             sendEvent('authenticate.login.clicked');
94
             sendEvent('authenticate.login.clicked');
80
             emitter.emit(UIEvents.AUTH_CLICKED);
95
             emitter.emit(UIEvents.AUTH_CLICKED);
81
         }
96
         }
82
 
97
 
83
         $('#profile_button_login').click(loginClicked);
98
         $('#profile_button_login').click(loginClicked);
84
 
99
 
85
-        // LOGOUT
86
-        function logoutClicked () {
87
-            let titleKey = "dialog.logoutTitle";
88
-            let msgKey = "dialog.logoutQuestion";
100
+        /**
101
+         *
102
+         */
103
+        function logoutClicked() {
104
+            const titleKey = 'dialog.logoutTitle';
105
+            const msgKey = 'dialog.logoutQuestion';
106
+
89
             sendEvent('authenticate.logout.clicked');
107
             sendEvent('authenticate.logout.clicked');
108
+
90
             // Ask for confirmation
109
             // Ask for confirmation
91
             APP.UI.messageHandler.openTwoButtonDialog({
110
             APP.UI.messageHandler.openTwoButtonDialog({
92
-                titleKey: titleKey,
93
-                msgKey: msgKey,
94
-                leftButtonKey: "dialog.Yes",
95
-                submitFunction: function (evt, yes) {
111
+                titleKey,
112
+                msgKey,
113
+                leftButtonKey: 'dialog.Yes',
114
+                submitFunction(evt, yes) {
96
                     if (yes) {
115
                     if (yes) {
97
                         emitter.emit(UIEvents.LOGOUT);
116
                         emitter.emit(UIEvents.LOGOUT);
98
                     }
117
                     }
107
      * Check if settings menu is visible or not.
126
      * Check if settings menu is visible or not.
108
      * @returns {boolean}
127
      * @returns {boolean}
109
      */
128
      */
110
-    isVisible () {
111
-        return UIUtil.isVisible(document.getElementById("profile_container"));
129
+    isVisible() {
130
+        return UIUtil.isVisible(document.getElementById('profile_container'));
112
     },
131
     },
113
 
132
 
114
     /**
133
     /**
115
      * Change user display name in the settings menu.
134
      * Change user display name in the settings menu.
116
      * @param {string} newDisplayName
135
      * @param {string} newDisplayName
117
      */
136
      */
118
-    changeDisplayName (newDisplayName) {
137
+    changeDisplayName(newDisplayName) {
119
         $('#setDisplayName').val(newDisplayName);
138
         $('#setDisplayName').val(newDisplayName);
120
     },
139
     },
121
 
140
 
123
      * Change user avatar in the settings menu.
142
      * Change user avatar in the settings menu.
124
      * @param {string} avatarUrl url of the new avatar
143
      * @param {string} avatarUrl url of the new avatar
125
      */
144
      */
126
-    changeAvatar (avatarUrl) {
145
+    changeAvatar(avatarUrl) {
127
         $('#avatar').attr('src', avatarUrl);
146
         $('#avatar').attr('src', avatarUrl);
128
     },
147
     },
129
 
148
 
131
      * Change the value of the field for the user email.
150
      * Change the value of the field for the user email.
132
      * @param {string} email the new value that will be displayed in the field.
151
      * @param {string} email the new value that will be displayed in the field.
133
      */
152
      */
134
-    changeEmail (email) {
153
+    changeEmail(email) {
135
         $('#setEmail').val(email);
154
         $('#setEmail').val(email);
136
     },
155
     },
137
 
156
 
139
      * Shows or hides authentication related buttons
158
      * Shows or hides authentication related buttons
140
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
159
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
141
      */
160
      */
142
-    showAuthenticationButtons (show) {
143
-        let id = 'profile_auth_container';
161
+    showAuthenticationButtons(show) {
162
+        const id = 'profile_auth_container';
163
+
144
         UIUtil.setVisible(id, show);
164
         UIUtil.setVisible(id, show);
145
     },
165
     },
146
 
166
 
148
      * Shows/hides login button.
168
      * Shows/hides login button.
149
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
169
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
150
      */
170
      */
151
-    showLoginButton (show) {
152
-        let id = 'profile_button_login';
171
+    showLoginButton(show) {
172
+        const id = 'profile_button_login';
153
 
173
 
154
         UIUtil.setVisible(id, show);
174
         UIUtil.setVisible(id, show);
155
     },
175
     },
158
      * Shows/hides logout button.
178
      * Shows/hides logout button.
159
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
179
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
160
      */
180
      */
161
-    showLogoutButton (show) {
162
-        let id = 'profile_button_logout';
181
+    showLogoutButton(show) {
182
+        const id = 'profile_button_logout';
163
 
183
 
164
         UIUtil.setVisible(id, show);
184
         UIUtil.setVisible(id, show);
165
     },
185
     },
168
      * Displays user's authenticated identity name (login).
188
      * Displays user's authenticated identity name (login).
169
      * @param {string} authIdentity identity name to be displayed.
189
      * @param {string} authIdentity identity name to be displayed.
170
      */
190
      */
171
-    setAuthenticatedIdentity (authIdentity) {
172
-        let id = 'profile_auth_identity';
191
+    setAuthenticatedIdentity(authIdentity) {
192
+        const id = 'profile_auth_identity';
173
 
193
 
174
-        UIUtil.setVisible(id, !!authIdentity);
194
+        UIUtil.setVisible(id, Boolean(authIdentity));
175
 
195
 
176
         $(`#${id}`).text(authIdentity ? authIdentity : '');
196
         $(`#${id}`).text(authIdentity ? authIdentity : '');
177
     }
197
     }

+ 58
- 40
modules/UI/side_pannels/settings/SettingsMenu.js View File

1
 /* global $, APP, AJS, interfaceConfig */
1
 /* global $, APP, AJS, interfaceConfig */
2
-import { LANGUAGES } from "../../../../react/features/base/i18n";
2
+import { LANGUAGES } from '../../../../react/features/base/i18n';
3
 import { openDeviceSelectionDialog }
3
 import { openDeviceSelectionDialog }
4
     from '../../../../react/features/device-selection';
4
     from '../../../../react/features/device-selection';
5
 
5
 
6
-import UIUtil from "../../util/UIUtil";
7
-import UIEvents from "../../../../service/UI/UIEvents";
6
+import UIUtil from '../../util/UIUtil';
7
+import UIEvents from '../../../../service/UI/UIEvents';
8
 
8
 
9
 const sidePanelsContainerId = 'sideToolbarContainer';
9
 const sidePanelsContainerId = 'sideToolbarContainer';
10
 const deviceSelectionButtonClasses
10
 const deviceSelectionButtonClasses
13
     <div id="settings_container" class="sideToolbarContainer__inner">
13
     <div id="settings_container" class="sideToolbarContainer__inner">
14
         <div class="title" data-i18n="settings.title"></div>
14
         <div class="title" data-i18n="settings.title"></div>
15
         <form class="aui">
15
         <form class="aui">
16
-            <div id="languagesSelectWrapper" 
16
+            <div id="languagesSelectWrapper"
17
                 class="sideToolbarBlock first hide">
17
                 class="sideToolbarBlock first hide">
18
                 <select id="languagesSelect"></select>
18
                 <select id="languagesSelect"></select>
19
             </div>
19
             </div>
20
             <div id="deviceOptionsWrapper" class="hide">
20
             <div id="deviceOptionsWrapper" class="hide">
21
-                <div id="deviceOptionsTitle" class="subTitle hide" 
21
+                <div id="deviceOptionsTitle" class="subTitle hide"
22
                     data-i18n="settings.audioVideo"></div>
22
                     data-i18n="settings.audioVideo"></div>
23
                 <div class="sideToolbarBlock first">
23
                 <div class="sideToolbarBlock first">
24
                     <button
24
                     <button
29
                 </div>
29
                 </div>
30
             </div>
30
             </div>
31
             <div id="moderatorOptionsWrapper" class="hide">
31
             <div id="moderatorOptionsWrapper" class="hide">
32
-                <div id="moderatorOptionsTitle" class="subTitle hide" 
32
+                <div id="moderatorOptionsTitle" class="subTitle hide"
33
                     data-i18n="settings.moderator"></div>
33
                     data-i18n="settings.moderator"></div>
34
                 <div id="startMutedOptions" class="hide">
34
                 <div id="startMutedOptions" class="hide">
35
                     <div class="sideToolbarBlock first">
35
                     <div class="sideToolbarBlock first">
36
                         <input type="checkbox" id="startAudioMuted">
36
                         <input type="checkbox" id="startAudioMuted">
37
-                        <label class="startMutedLabel" for="startAudioMuted" 
37
+                        <label class="startMutedLabel" for="startAudioMuted"
38
                             data-i18n="settings.startAudioMuted"></label>
38
                             data-i18n="settings.startAudioMuted"></label>
39
                     </div>
39
                     </div>
40
                     <div class="sideToolbarBlock">
40
                     <div class="sideToolbarBlock">
41
                         <input type="checkbox" id="startVideoMuted">
41
                         <input type="checkbox" id="startVideoMuted">
42
-                        <label class="startMutedLabel" for="startVideoMuted" 
42
+                        <label class="startMutedLabel" for="startVideoMuted"
43
                             data-i18n="settings.startVideoMuted"></label>
43
                             data-i18n="settings.startVideoMuted"></label>
44
                     </div>
44
                     </div>
45
                 </div>
45
                 </div>
46
                 <div id="followMeOptions" class="hide">
46
                 <div id="followMeOptions" class="hide">
47
                     <div class="sideToolbarBlock">
47
                     <div class="sideToolbarBlock">
48
                         <input type="checkbox" id="followMeCheckBox">
48
                         <input type="checkbox" id="followMeCheckBox">
49
-                        <label class="followMeLabel" for="followMeCheckBox" 
49
+                        <label class="followMeLabel" for="followMeCheckBox"
50
                             data-i18n="settings.followMe"></label>
50
                             data-i18n="settings.followMe"></label>
51
                     </div>
51
                     </div>
52
                 </div>
52
                 </div>
54
         </form>
54
         </form>
55
     </div>`;
55
     </div>`;
56
 
56
 
57
+/**
58
+ *
59
+ */
57
 function initHTML() {
60
 function initHTML() {
58
     $(`#${sidePanelsContainerId}`)
61
     $(`#${sidePanelsContainerId}`)
59
         .append(htmlStr);
62
         .append(htmlStr);
63
+
60
     // make sure we translate the panel, as adding it can be after i18n
64
     // make sure we translate the panel, as adding it can be after i18n
61
     // library had initialized and translated already present html
65
     // library had initialized and translated already present html
62
     APP.translation.translateElement($(`#${sidePanelsContainerId}`));
66
     APP.translation.translateElement($(`#${sidePanelsContainerId}`));
70
  * @returns {string}
74
  * @returns {string}
71
  */
75
  */
72
 function generateLanguagesOptions(items, currentLang) {
76
 function generateLanguagesOptions(items, currentLang) {
73
-    return items.map(function (lang) {
74
-        let attrs = {
77
+    return items.map(lang => {
78
+        const attrs = {
75
             value: lang,
79
             value: lang,
76
             'data-i18n': `languages:${lang}`
80
             'data-i18n': `languages:${lang}`
77
         };
81
         };
80
             attrs.selected = 'selected';
84
             attrs.selected = 'selected';
81
         }
85
         }
82
 
86
 
83
-        let attrsStr = UIUtil.attrsToString(attrs);
87
+        const attrsStr = UIUtil.attrsToString(attrs);
88
+
89
+
84
         return `<option ${attrsStr}></option>`;
90
         return `<option ${attrsStr}></option>`;
85
     }).join('');
91
     }).join('');
86
 }
92
 }
101
 }
107
 }
102
 
108
 
103
 export default {
109
 export default {
104
-    init (emitter) {
110
+    init(emitter) {
105
         initHTML();
111
         initHTML();
106
-        //LANGUAGES BOX
112
+
113
+        // LANGUAGES BOX
107
         if (UIUtil.isSettingEnabled('language')) {
114
         if (UIUtil.isSettingEnabled('language')) {
108
             const wrapperId = 'languagesSelectWrapper';
115
             const wrapperId = 'languagesSelectWrapper';
109
             const selectId = 'languagesSelect';
116
             const selectId = 'languagesSelect';
110
             const selectEl = AJS.$(`#${selectId}`);
117
             const selectEl = AJS.$(`#${selectId}`);
111
-            let selectInput;
118
+            let selectInput; // eslint-disable-line prefer-const
112
 
119
 
113
             selectEl.html(generateLanguagesOptions(
120
             selectEl.html(generateLanguagesOptions(
114
                 LANGUAGES,
121
                 LANGUAGES,
121
                 APP.translation.translateElement(selectInput);
128
                 APP.translation.translateElement(selectInput);
122
                 emitter.emit(UIEvents.LANG_CHANGED, val);
129
                 emitter.emit(UIEvents.LANG_CHANGED, val);
123
             });
130
             });
124
-            //find new selectInput element
131
+
132
+            // find new selectInput element
125
             selectInput = $(`#s2id_${selectId} .select2-chosen`);
133
             selectInput = $(`#s2id_${selectId} .select2-chosen`);
126
-            //first select fix for languages options
127
-            selectInput[0].dataset.i18n =
128
-                `languages:${APP.translation.getCurrentLanguage()}`;
134
+
135
+            // first select fix for languages options
136
+            selectInput[0].dataset.i18n
137
+                = `languages:${APP.translation.getCurrentLanguage()}`;
129
 
138
 
130
             // translate selectInput, which is the currently selected language
139
             // translate selectInput, which is the currently selected language
131
             // otherwise there will be no selected option
140
             // otherwise there will be no selected option
133
             APP.translation.translateElement(selectEl);
142
             APP.translation.translateElement(selectEl);
134
 
143
 
135
             APP.translation.addLanguageChangedListener(
144
             APP.translation.addLanguageChangedListener(
136
-                lng => selectInput[0].dataset.i18n = `languages:${lng}`);
145
+                lng => {
146
+                    selectInput[0].dataset.i18n = `languages:${lng}`;
147
+                });
137
 
148
 
138
             UIUtil.setVisible(wrapperId, true);
149
             UIUtil.setVisible(wrapperId, true);
139
         }
150
         }
151
+
140
         // DEVICES LIST
152
         // DEVICES LIST
141
         if (UIUtil.isSettingEnabled('devices')) {
153
         if (UIUtil.isSettingEnabled('devices')) {
142
             const wrapperId = 'deviceOptionsWrapper';
154
             const wrapperId = 'deviceOptionsWrapper';
145
                 APP.store.dispatch(openDeviceSelectionDialog()));
157
                 APP.store.dispatch(openDeviceSelectionDialog()));
146
 
158
 
147
             // Only show the subtitle if this isn't the only setting section.
159
             // Only show the subtitle if this isn't the only setting section.
148
-            if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
149
-                UIUtil.setVisible("deviceOptionsTitle", true);
160
+            if (interfaceConfig.SETTINGS_SECTIONS.length > 1) {
161
+                UIUtil.setVisible('deviceOptionsTitle', true);
162
+            }
150
 
163
 
151
             UIUtil.setVisible(wrapperId, true);
164
             UIUtil.setVisible(wrapperId, true);
152
         }
165
         }
166
+
153
         // MODERATOR
167
         // MODERATOR
154
         if (UIUtil.isSettingEnabled('moderator')) {
168
         if (UIUtil.isSettingEnabled('moderator')) {
155
             const wrapperId = 'moderatorOptionsWrapper';
169
             const wrapperId = 'moderatorOptionsWrapper';
156
 
170
 
157
             // START MUTED
171
             // START MUTED
158
-            $("#startMutedOptions").change(function () {
159
-                let startAudioMuted = $("#startAudioMuted").is(":checked");
160
-                let startVideoMuted = $("#startVideoMuted").is(":checked");
172
+            $('#startMutedOptions').change(() => {
173
+                const startAudioMuted = $('#startAudioMuted').is(':checked');
174
+                const startVideoMuted = $('#startVideoMuted').is(':checked');
161
 
175
 
162
                 emitter.emit(
176
                 emitter.emit(
163
                     UIEvents.START_MUTED_CHANGED,
177
                     UIEvents.START_MUTED_CHANGED,
168
 
182
 
169
             // FOLLOW ME
183
             // FOLLOW ME
170
             const followMeToggle = document.getElementById('followMeCheckBox');
184
             const followMeToggle = document.getElementById('followMeCheckBox');
185
+
171
             followMeToggle.addEventListener('change', () => {
186
             followMeToggle.addEventListener('change', () => {
172
                 const isFollowMeEnabled = followMeToggle.checked;
187
                 const isFollowMeEnabled = followMeToggle.checked;
188
+
173
                 emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
189
                 emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
174
             });
190
             });
175
 
191
 
181
      * If start audio muted/start video muted options should be visible or not.
197
      * If start audio muted/start video muted options should be visible or not.
182
      * @param {boolean} show
198
      * @param {boolean} show
183
      */
199
      */
184
-    showStartMutedOptions (show) {
200
+    showStartMutedOptions(show) {
185
         if (show && UIUtil.isSettingEnabled('moderator')) {
201
         if (show && UIUtil.isSettingEnabled('moderator')) {
186
             // Only show the subtitle if this isn't the only setting section.
202
             // Only show the subtitle if this isn't the only setting section.
187
-            if (!$("#moderatorOptionsTitle").is(":visible")
188
-                    && interfaceConfig.SETTINGS_SECTIONS.length > 1)
189
-                UIUtil.setVisible("moderatorOptionsTitle", true);
203
+            if (!$('#moderatorOptionsTitle').is(':visible')
204
+                    && interfaceConfig.SETTINGS_SECTIONS.length > 1) {
205
+                UIUtil.setVisible('moderatorOptionsTitle', true);
206
+            }
190
 
207
 
191
-            UIUtil.setVisible("startMutedOptions", true);
208
+            UIUtil.setVisible('startMutedOptions', true);
192
         } else {
209
         } else {
193
             // Only show the subtitle if this isn't the only setting section.
210
             // Only show the subtitle if this isn't the only setting section.
194
-            if ($("#moderatorOptionsTitle").is(":visible"))
195
-                UIUtil.setVisible("moderatorOptionsTitle", false);
211
+            if ($('#moderatorOptionsTitle').is(':visible')) {
212
+                UIUtil.setVisible('moderatorOptionsTitle', false);
213
+            }
196
 
214
 
197
-            UIUtil.setVisible("startMutedOptions", false);
215
+            UIUtil.setVisible('startMutedOptions', false);
198
         }
216
         }
199
     },
217
     },
200
 
218
 
201
-    updateStartMutedBox (startAudioMuted, startVideoMuted) {
202
-        $("#startAudioMuted").attr("checked", startAudioMuted);
203
-        $("#startVideoMuted").attr("checked", startVideoMuted);
219
+    updateStartMutedBox(startAudioMuted, startVideoMuted) {
220
+        $('#startAudioMuted').attr('checked', startAudioMuted);
221
+        $('#startVideoMuted').attr('checked', startVideoMuted);
204
     },
222
     },
205
 
223
 
206
     /**
224
     /**
208
      *
226
      *
209
      * @param {boolean} show {true} to show those options, {false} to hide them
227
      * @param {boolean} show {true} to show those options, {false} to hide them
210
      */
228
      */
211
-    showFollowMeOptions (show) {
229
+    showFollowMeOptions(show) {
212
         UIUtil.setVisible(
230
         UIUtil.setVisible(
213
-            "followMeOptions",
231
+            'followMeOptions',
214
             show && UIUtil.isSettingEnabled('moderator'));
232
             show && UIUtil.isSettingEnabled('moderator'));
215
     },
233
     },
216
 
234
 
218
      * Check if settings menu is visible or not.
236
      * Check if settings menu is visible or not.
219
      * @returns {boolean}
237
      * @returns {boolean}
220
      */
238
      */
221
-    isVisible () {
222
-        return UIUtil.isVisible(document.getElementById("settings_container"));
239
+    isVisible() {
240
+        return UIUtil.isVisible(document.getElementById('settings_container'));
223
     }
241
     }
224
 };
242
 };

+ 117
- 84
modules/UI/util/MessageHandler.js View File

1
 /* global $, APP */
1
 /* global $, APP */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
2
+const logger = require('jitsi-meet-logger').getLogger(__filename);
3
 
3
 
4
 import jitsiLocalStorage from '../../util/JitsiLocalStorage';
4
 import jitsiLocalStorage from '../../util/JitsiLocalStorage';
5
 
5
 
31
  * @returns {string}
31
  * @returns {string}
32
  */
32
  */
33
 function generateDontShowCheckbox(options) {
33
 function generateDontShowCheckbox(options) {
34
-    if(!isDontShowAgainEnabled(options)) {
35
-        return "";
34
+    if (!isDontShowAgainEnabled(options)) {
35
+        return '';
36
     }
36
     }
37
 
37
 
38
-    let checked
39
-        = (options.checked === true) ? "checked" : "";
38
+    const checked
39
+        = options.checked === true ? 'checked' : '';
40
+
41
+
40
     return `<br />
42
     return `<br />
41
         <label>
43
         <label>
42
             <input type='checkbox' ${checked} id='${options.id}' />
44
             <input type='checkbox' ${checked} id='${options.id}' />
54
  * false otherwise.
56
  * false otherwise.
55
  */
57
  */
56
 function dontShowTheDialog(options) {
58
 function dontShowTheDialog(options) {
57
-    if(isDontShowAgainEnabled(options)) {
58
-        if(jitsiLocalStorage.getItem(options.localStorageKey || options.id)
59
-            === "true") {
59
+    if (isDontShowAgainEnabled(options)) {
60
+        if (jitsiLocalStorage.getItem(options.localStorageKey || options.id)
61
+            === 'true') {
60
             return true;
62
             return true;
61
         }
63
         }
62
     }
64
     }
65
+
63
     return false;
66
     return false;
64
 }
67
 }
65
 
68
 
76
  * @returns {Function} wrapped function
79
  * @returns {Function} wrapped function
77
  */
80
  */
78
 function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
81
 function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
79
-    if(isDontShowAgainEnabled(options)) {
82
+    if (isDontShowAgainEnabled(options)) {
80
         return (...args) => {
83
         return (...args) => {
81
             logger.debug(args, options.buttonValues);
84
             logger.debug(args, options.buttonValues);
82
-            //args[1] is the value associated with the pressed button
83
-            if(!options.buttonValues || options.buttonValues.length === 0
84
-                || options.buttonValues.indexOf(args[1]) !== -1 ) {
85
-                let checkbox = $(`#${options.id}`);
85
+
86
+            // args[1] is the value associated with the pressed button
87
+            if (!options.buttonValues || options.buttonValues.length === 0
88
+                || options.buttonValues.indexOf(args[1]) !== -1) {
89
+                const checkbox = $(`#${options.id}`);
90
+
86
                 if (checkbox.length) {
91
                 if (checkbox.length) {
87
                     jitsiLocalStorage.setItem(
92
                     jitsiLocalStorage.setItem(
88
                         options.localStorageKey || options.id,
93
                         options.localStorageKey || options.id,
89
-                        checkbox.prop("checked"));
94
+                        checkbox.prop('checked'));
90
                 }
95
                 }
91
             }
96
             }
92
             submitFunction(...args);
97
             submitFunction(...args);
93
         };
98
         };
94
-    } else {
95
-        return submitFunction;
96
     }
99
     }
100
+
101
+    return submitFunction;
102
+
97
 }
103
 }
98
 
104
 
99
 /**
105
 /**
102
  * @returns {boolean} true if enabled and false if not.
108
  * @returns {boolean} true if enabled and false if not.
103
  */
109
  */
104
 function isDontShowAgainEnabled(options) {
110
 function isDontShowAgainEnabled(options) {
105
-    return typeof options === "object";
111
+    return typeof options === 'object';
106
 }
112
 }
107
 
113
 
108
-var messageHandler = {
109
-    OK: "dialog.OK",
110
-    CANCEL: "dialog.Cancel",
114
+const messageHandler = {
115
+    OK: 'dialog.OK',
116
+    CANCEL: 'dialog.Cancel',
111
 
117
 
112
     /**
118
     /**
113
      * Shows a message to the user.
119
      * Shows a message to the user.
120
      * the prompt is closed (optional)
126
      * the prompt is closed (optional)
121
      * @return the prompt that was created, or null
127
      * @return the prompt that was created, or null
122
      */
128
      */
129
+    // eslint-disable-next-line max-params
123
     openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
130
     openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
124
-        if (!popupEnabled)
131
+        if (!popupEnabled) {
125
             return null;
132
             return null;
133
+        }
126
 
134
 
127
-        let dialog = $.prompt(
135
+        const dialog = $.prompt(
128
             APP.translation.generateTranslationHTML(messageKey, i18nOptions),
136
             APP.translation.generateTranslationHTML(messageKey, i18nOptions),
129
             {
137
             {
130
                 title: this._getFormattedTitleString(titleKey),
138
                 title: this._getFormattedTitleString(titleKey),
131
                 persistent: false,
139
                 persistent: false,
132
                 promptspeed: 0,
140
                 promptspeed: 0,
133
                 classes: this._getDialogClasses(),
141
                 classes: this._getDialogClasses(),
142
+                // eslint-disable-next-line max-params
134
                 close(e, v, m, f) {
143
                 close(e, v, m, f) {
135
-                    if(closeFunction)
144
+                    if (closeFunction) {
136
                         closeFunction(e, v, m, f);
145
                         closeFunction(e, v, m, f);
146
+                    }
137
                 }
147
                 }
138
             });
148
             });
149
+
139
         APP.translation.translateElement(dialog, i18nOptions);
150
         APP.translation.translateElement(dialog, i18nOptions);
151
+
140
         return $.prompt.getApi();
152
         return $.prompt.getApi();
141
     },
153
     },
154
+
142
     /**
155
     /**
143
      * Shows a message to the user with two buttons: first is given as a
156
      * Shows a message to the user with two buttons: first is given as a
144
      * parameter and the second is Cancel.
157
      * parameter and the second is Cancel.
169
      * storage. if not provided dontShowAgain.id will be used.
182
      * storage. if not provided dontShowAgain.id will be used.
170
      * @return the prompt that was created, or null
183
      * @return the prompt that was created, or null
171
      */
184
      */
172
-    openTwoButtonDialog: function(options) {
173
-        let {
185
+    openTwoButtonDialog(options) {
186
+        const {
174
             titleKey,
187
             titleKey,
175
             msgKey,
188
             msgKey,
176
             msgString,
189
             msgString,
182
             size,
195
             size,
183
             defaultButton,
196
             defaultButton,
184
             wrapperClass,
197
             wrapperClass,
185
-            classes,
186
             dontShowAgain
198
             dontShowAgain
187
         } = options;
199
         } = options;
188
 
200
 
189
-        if (!popupEnabled || twoButtonDialog)
201
+        let { classes } = options;
202
+
203
+        if (!popupEnabled || twoButtonDialog) {
190
             return null;
204
             return null;
205
+        }
191
 
206
 
192
-        if(dontShowTheDialog(dontShowAgain)) {
207
+        if (dontShowTheDialog(dontShowAgain)) {
193
             // Maybe we should pass some parameters here? I'm not sure
208
             // Maybe we should pass some parameters here? I'm not sure
194
             // and currently we don't need any parameters.
209
             // and currently we don't need any parameters.
195
             submitFunction();
210
             submitFunction();
211
+
196
             return null;
212
             return null;
197
         }
213
         }
198
 
214
 
199
-        var buttons = [];
215
+        const buttons = [];
216
+
217
+        const leftButton = leftButtonKey
218
+            ? APP.translation.generateTranslationHTML(leftButtonKey)
219
+            : APP.translation.generateTranslationHTML('dialog.Submit');
200
 
220
 
201
-        var leftButton = leftButtonKey ?
202
-            APP.translation.generateTranslationHTML(leftButtonKey) :
203
-            APP.translation.generateTranslationHTML('dialog.Submit');
204
-        buttons.push({ title: leftButton, value: true});
221
+        buttons.push({ title: leftButton,
222
+            value: true });
205
 
223
 
206
-        var cancelButton
207
-            = APP.translation.generateTranslationHTML("dialog.Cancel");
208
-        buttons.push({title: cancelButton, value: false});
224
+        const cancelButton
225
+            = APP.translation.generateTranslationHTML('dialog.Cancel');
226
+
227
+        buttons.push({ title: cancelButton,
228
+            value: false });
229
+
230
+        let message = msgString;
209
 
231
 
210
-        var message = msgString;
211
         if (msgKey) {
232
         if (msgKey) {
212
             message = APP.translation.generateTranslationHTML(msgKey);
233
             message = APP.translation.generateTranslationHTML(msgKey);
213
         }
234
         }
220
         twoButtonDialog = $.prompt(message, {
241
         twoButtonDialog = $.prompt(message, {
221
             title: this._getFormattedTitleString(titleKey),
242
             title: this._getFormattedTitleString(titleKey),
222
             persistent: false,
243
             persistent: false,
223
-            buttons: buttons,
224
-            defaultButton: defaultButton,
225
-            focus: focus,
244
+            buttons,
245
+            defaultButton,
246
+            focus,
226
             loaded: loadedFunction,
247
             loaded: loadedFunction,
227
             promptspeed: 0,
248
             promptspeed: 0,
228
             classes,
249
             classes,
229
             submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
250
             submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
230
-                function (e, v, m, f) {
251
+                (e, v, m, f) => { // eslint-disable-line max-params
231
                     twoButtonDialog = null;
252
                     twoButtonDialog = null;
232
                     if (v && submitFunction) {
253
                     if (v && submitFunction) {
233
                         submitFunction(e, v, m, f);
254
                         submitFunction(e, v, m, f);
234
                     }
255
                     }
235
                 }),
256
                 }),
236
-            close: function (e, v, m, f) {
257
+            close(e, v, m, f) { // eslint-disable-line max-params
237
                 twoButtonDialog = null;
258
                 twoButtonDialog = null;
238
                 if (closeFunction) {
259
                 if (closeFunction) {
239
                     closeFunction(e, v, m, f);
260
                     closeFunction(e, v, m, f);
241
             }
262
             }
242
         });
263
         });
243
         APP.translation.translateElement(twoButtonDialog);
264
         APP.translation.translateElement(twoButtonDialog);
265
+
244
         return $.prompt.getApi();
266
         return $.prompt.getApi();
245
     },
267
     },
246
 
268
 
270
      * @param {string} dontShowAgain.localStorageKey the key for the local
292
      * @param {string} dontShowAgain.localStorageKey the key for the local
271
      * storage. if not provided dontShowAgain.id will be used.
293
      * storage. if not provided dontShowAgain.id will be used.
272
      */
294
      */
273
-    openDialog(
295
+    openDialog(// eslint-disable-line max-params
274
             titleKey,
296
             titleKey,
275
             msgString,
297
             msgString,
276
             persistent,
298
             persistent,
279
             loadedFunction,
301
             loadedFunction,
280
             closeFunction,
302
             closeFunction,
281
             dontShowAgain) {
303
             dontShowAgain) {
282
-        if (!popupEnabled)
304
+        if (!popupEnabled) {
283
             return;
305
             return;
306
+        }
284
 
307
 
285
-        if(dontShowTheDialog(dontShowAgain)) {
308
+        if (dontShowTheDialog(dontShowAgain)) {
286
             // Maybe we should pass some parameters here? I'm not sure
309
             // Maybe we should pass some parameters here? I'm not sure
287
             // and currently we don't need any parameters.
310
             // and currently we don't need any parameters.
288
             submitFunction();
311
             submitFunction();
312
+
289
             return;
313
             return;
290
         }
314
         }
291
 
315
 
292
-        let args = {
316
+        const args = {
293
             title: this._getFormattedTitleString(titleKey),
317
             title: this._getFormattedTitleString(titleKey),
294
-            persistent: persistent,
295
-            buttons: buttons,
318
+            persistent,
319
+            buttons,
296
             defaultButton: 1,
320
             defaultButton: 1,
297
             promptspeed: 0,
321
             promptspeed: 0,
298
-            loaded: function() {
322
+            loaded() {
299
                 if (loadedFunction) {
323
                 if (loadedFunction) {
324
+                    // eslint-disable-next-line prefer-rest-params
300
                     loadedFunction.apply(this, arguments);
325
                     loadedFunction.apply(this, arguments);
301
                 }
326
                 }
327
+
302
                 // Hide the close button
328
                 // Hide the close button
303
                 if (persistent) {
329
                 if (persistent) {
304
-                    $(".jqiclose", this).hide();
330
+                    $('.jqiclose', this).hide();
305
                 }
331
                 }
306
             },
332
             },
307
             submit: dontShowAgainSubmitFunctionWrapper(
333
             submit: dontShowAgainSubmitFunctionWrapper(
314
             args.closeText = '';
340
             args.closeText = '';
315
         }
341
         }
316
 
342
 
317
-        let dialog = $.prompt(
343
+        const dialog = $.prompt(
318
             msgString + generateDontShowCheckbox(dontShowAgain), args);
344
             msgString + generateDontShowCheckbox(dontShowAgain), args);
345
+
319
         APP.translation.translateElement(dialog);
346
         APP.translation.translateElement(dialog);
347
+
320
         return $.prompt.getApi();
348
         return $.prompt.getApi();
321
     },
349
     },
322
 
350
 
326
      * @return the title string formatted as a div.
354
      * @return the title string formatted as a div.
327
      */
355
      */
328
     _getFormattedTitleString(titleKey) {
356
     _getFormattedTitleString(titleKey) {
329
-        let $titleString = $('<h2>');
357
+        const $titleString = $('<h2>');
358
+
330
         $titleString.addClass('aui-dialog2-header-main');
359
         $titleString.addClass('aui-dialog2-header-main');
331
-        $titleString.attr('data-i18n',titleKey);
332
-        return $('<div>').append($titleString).html();
360
+        $titleString.attr('data-i18n', titleKey);
361
+
362
+        return $('<div>').append($titleString)
363
+.html();
333
     },
364
     },
334
 
365
 
335
     /**
366
     /**
359
      * @param options impromptu options
390
      * @param options impromptu options
360
      * @param translateOptions options passed to translation
391
      * @param translateOptions options passed to translation
361
      */
392
      */
362
-    openDialogWithStates: function (statesObject, options, translateOptions) {
363
-        if (!popupEnabled)
393
+    openDialogWithStates(statesObject, options, translateOptions) {
394
+        if (!popupEnabled) {
364
             return;
395
             return;
365
-        let { classes, size } = options;
366
-        let defaultClasses = this._getDialogClasses(size);
396
+        }
397
+        const { classes, size } = options;
398
+        const defaultClasses = this._getDialogClasses(size);
399
+
367
         options.classes = Object.assign({}, defaultClasses, classes);
400
         options.classes = Object.assign({}, defaultClasses, classes);
368
         options.promptspeed = options.promptspeed || 0;
401
         options.promptspeed = options.promptspeed || 0;
369
 
402
 
370
-        for (let state in statesObject) {
371
-            let currentState = statesObject[state];
372
-            if(currentState.titleKey) {
403
+        for (const state in statesObject) { // eslint-disable-line guard-for-in
404
+            const currentState = statesObject[state];
405
+
406
+            if (currentState.titleKey) {
373
                 currentState.title
407
                 currentState.title
374
                     = this._getFormattedTitleString(currentState.titleKey);
408
                     = this._getFormattedTitleString(currentState.titleKey);
375
             }
409
             }
376
         }
410
         }
377
-        let dialog = $.prompt(statesObject, options);
411
+        const dialog = $.prompt(statesObject, options);
412
+
378
         APP.translation.translateElement(dialog, translateOptions);
413
         APP.translation.translateElement(dialog, translateOptions);
414
+
379
         return $.prompt.getApi();
415
         return $.prompt.getApi();
380
     },
416
     },
381
 
417
 
392
      * @returns {object} popup window object if opened successfully or undefined
428
      * @returns {object} popup window object if opened successfully or undefined
393
      *          in case we failed to open it(popup blocked)
429
      *          in case we failed to open it(popup blocked)
394
      */
430
      */
395
-    openCenteredPopup: function (url, w, h, onPopupClosed) {
396
-        if (!popupEnabled)
431
+    // eslint-disable-next-line max-params
432
+    openCenteredPopup(url, w, h, onPopupClosed) {
433
+        if (!popupEnabled) {
397
             return;
434
             return;
435
+        }
398
 
436
 
399
-        var l = window.screenX + (window.innerWidth / 2) - (w / 2);
400
-        var t = window.screenY + (window.innerHeight / 2) - (h / 2);
401
-        var popup = window.open(
437
+        const l = window.screenX + (window.innerWidth / 2) - (w / 2);
438
+        const t = window.screenY + (window.innerHeight / 2) - (h / 2);
439
+        const popup = window.open(
402
             url, '_blank',
440
             url, '_blank',
403
-            'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
441
+            String(`top=${t}, left=${l}, width=${w}, height=${h}`));
442
+
404
         if (popup && onPopupClosed) {
443
         if (popup && onPopupClosed) {
405
-            var pollTimer = window.setInterval(function () {
444
+            const pollTimer = window.setInterval(() => {
406
                 if (popup.closed !== false) {
445
                 if (popup.closed !== false) {
407
                     window.clearInterval(pollTimer);
446
                     window.clearInterval(pollTimer);
408
                     onPopupClosed();
447
                     onPopupClosed();
420
      * @param msgKey the text of the message
459
      * @param msgKey the text of the message
421
      * @param error the error that is being reported
460
      * @param error the error that is being reported
422
      */
461
      */
423
-    openReportDialog: function(titleKey, msgKey, error) {
462
+    openReportDialog(titleKey, msgKey, error) {
424
         this.openMessageDialog(titleKey, msgKey);
463
         this.openMessageDialog(titleKey, msgKey);
425
         logger.log(error);
464
         logger.log(error);
426
-        //FIXME send the error to the server
465
+
466
+        // FIXME send the error to the server
427
     },
467
     },
428
 
468
 
429
     /**
469
     /**
431
      * @param titleKey the title of the message.
471
      * @param titleKey the title of the message.
432
      * @param msgKey the text of the message.
472
      * @param msgKey the text of the message.
433
      */
473
      */
434
-    showError: function(titleKey, msgKey) {
435
-
436
-        if (!titleKey) {
437
-            titleKey = "dialog.oops";
438
-        }
439
-        if (!msgKey) {
440
-            msgKey = "dialog.defaultError";
441
-        }
474
+    showError(titleKey = 'dialog.oops', msgKey = 'dialog.defaultError') {
442
         messageHandler.openMessageDialog(titleKey, msgKey);
475
         messageHandler.openMessageDialog(titleKey, msgKey);
443
     },
476
     },
444
 
477
 
454
      * @param messageArguments object with the arguments for the message.
487
      * @param messageArguments object with the arguments for the message.
455
      * @param optional configurations for the notification (e.g. timeout)
488
      * @param optional configurations for the notification (e.g. timeout)
456
      */
489
      */
457
-    participantNotification(
490
+    participantNotification( // eslint-disable-line max-params
458
             displayName,
491
             displayName,
459
             displayNameKey,
492
             displayNameKey,
460
             cls,
493
             cls,
484
      * translation.
517
      * translation.
485
      * @returns {void}
518
      * @returns {void}
486
      */
519
      */
487
-    notify: function(titleKey, messageKey, messageArguments) {
520
+    notify(titleKey, messageKey, messageArguments) {
488
         this.participantNotification(
521
         this.participantNotification(
489
             null, titleKey, null, messageKey, messageArguments);
522
             null, titleKey, null, messageKey, messageArguments);
490
     },
523
     },
491
 
524
 
492
-    enablePopups: function (enable) {
525
+    enablePopups(enable) {
493
         popupEnabled = enable;
526
         popupEnabled = enable;
494
     },
527
     },
495
 
528
 
498
      * false otherwise
531
      * false otherwise
499
      * @returns {boolean} isOpened
532
      * @returns {boolean} isOpened
500
      */
533
      */
501
-    isDialogOpened: function () {
502
-        return !!$.prompt.getCurrentStateName();
534
+    isDialogOpened() {
535
+        return Boolean($.prompt.getCurrentStateName());
503
     }
536
     }
504
 };
537
 };
505
 
538
 

+ 59
- 41
modules/UI/util/UIUtil.js View File

31
 /**
31
 /**
32
  * Created by hristo on 12/22/14.
32
  * Created by hristo on 12/22/14.
33
  */
33
  */
34
-var UIUtil = {
34
+const UIUtil = {
35
 
35
 
36
     /**
36
     /**
37
      * Returns the available video width.
37
      * Returns the available video width.
43
     /**
43
     /**
44
      * Changes the style class of the element given by id.
44
      * Changes the style class of the element given by id.
45
      */
45
      */
46
-    buttonClick: function(id, classname) {
46
+    buttonClick(id, classname) {
47
         // add the class to the clicked element
47
         // add the class to the clicked element
48
-        $("#" + id).toggleClass(classname);
48
+        $(`#${id}`).toggleClass(classname);
49
     },
49
     },
50
+
50
     /**
51
     /**
51
      * Returns the text width for the given element.
52
      * Returns the text width for the given element.
52
      *
53
      *
53
      * @param el the element
54
      * @param el the element
54
      */
55
      */
55
     getTextWidth(el) {
56
     getTextWidth(el) {
56
-        return (el.clientWidth + 1);
57
+        return el.clientWidth + 1;
57
     },
58
     },
58
 
59
 
59
     /**
60
     /**
62
      * @param el the element
63
      * @param el the element
63
      */
64
      */
64
     getTextHeight(el) {
65
     getTextHeight(el) {
65
-        return (el.clientHeight + 1);
66
+        return el.clientHeight + 1;
66
     },
67
     },
67
 
68
 
68
     /**
69
     /**
78
      * Escapes the given text.
79
      * Escapes the given text.
79
      */
80
      */
80
     escapeHtml(unsafeText) {
81
     escapeHtml(unsafeText) {
81
-        return $('<div/>').text(unsafeText).html();
82
+        return $('<div/>').text(unsafeText)
83
+            .html();
82
     },
84
     },
83
 
85
 
84
     /**
86
     /**
88
      * @returns {string} unescaped html string.
90
      * @returns {string} unescaped html string.
89
      */
91
      */
90
     unescapeHtml(safe) {
92
     unescapeHtml(safe) {
91
-        return $('<div />').html(safe).text();
93
+        return $('<div />').html(safe)
94
+            .text();
92
     },
95
     },
93
 
96
 
94
     imageToGrayScale(canvas) {
97
     imageToGrayScale(canvas) {
95
-        var context = canvas.getContext('2d');
96
-        var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
97
-        var pixels  = imgData.data;
98
-
99
-        for (var i = 0, n = pixels.length; i < n; i += 4) {
100
-            var grayscale
101
-                = pixels[i] * 0.3 + pixels[i+1] * 0.59 + pixels[i+2] * 0.11;
102
-            pixels[i  ] = grayscale;        // red
103
-            pixels[i+1] = grayscale;        // green
104
-            pixels[i+2] = grayscale;        // blue
98
+        const context = canvas.getContext('2d');
99
+        const imgData = context.getImageData(0, 0, canvas.width, canvas.height);
100
+        const pixels = imgData.data;
101
+
102
+        for (let i = 0, n = pixels.length; i < n; i += 4) {
103
+            const grayscale
104
+                = (pixels[i] * 0.3)
105
+                    + (pixels[i + 1] * 0.59)
106
+                    + (pixels[i + 2] * 0.11);
107
+
108
+            pixels[i] = grayscale; // red
109
+            pixels[i + 1] = grayscale; // green
110
+            pixels[i + 2] = grayscale; // blue
105
             // pixels[i+3]              is alpha
111
             // pixels[i+3]              is alpha
106
         }
112
         }
113
+
107
         // redraw the image in black & white
114
         // redraw the image in black & white
108
         context.putImageData(imgData, 0, 0);
115
         context.putImageData(imgData, 0, 0);
109
     },
116
     },
114
      * @param newChild the new element that will be inserted into the container
121
      * @param newChild the new element that will be inserted into the container
115
      */
122
      */
116
     prependChild(container, newChild) {
123
     prependChild(container, newChild) {
117
-        var firstChild = container.childNodes[0];
124
+        const firstChild = container.childNodes[0];
125
+
118
         if (firstChild) {
126
         if (firstChild) {
119
             container.insertBefore(newChild, firstChild);
127
             container.insertBefore(newChild, firstChild);
120
         } else {
128
         } else {
152
      */
160
      */
153
     setVisible(id, visible) {
161
     setVisible(id, visible) {
154
         let element;
162
         let element;
163
+
155
         if (id instanceof HTMLElement) {
164
         if (id instanceof HTMLElement) {
156
             element = id;
165
             element = id;
157
         } else {
166
         } else {
162
             return;
171
             return;
163
         }
172
         }
164
 
173
 
165
-        if (!visible)
174
+        if (!visible) {
166
             element.classList.add('hide');
175
             element.classList.add('hide');
167
-        else if (element.classList.contains('hide')) {
176
+        } else if (element.classList.contains('hide')) {
168
             element.classList.remove('hide');
177
             element.classList.remove('hide');
169
         }
178
         }
170
 
179
 
171
-        let type = this._getElementDefaultDisplay(element.tagName);
172
-        let className = SHOW_CLASSES[type];
180
+        const type = this._getElementDefaultDisplay(element.tagName);
181
+        const className = SHOW_CLASSES[type];
173
 
182
 
174
         if (visible) {
183
         if (visible) {
175
             element.classList.add(className);
184
             element.classList.add(className);
176
-        }
177
-        else if (element.classList.contains(className))
185
+        } else if (element.classList.contains(className)) {
178
             element.classList.remove(className);
186
             element.classList.remove(className);
187
+        }
179
     },
188
     },
180
 
189
 
181
     /**
190
     /**
185
      * @private
194
      * @private
186
      */
195
      */
187
     _getElementDefaultDisplay(tag) {
196
     _getElementDefaultDisplay(tag) {
188
-        let tempElement = document.createElement(tag);
197
+        const tempElement = document.createElement(tag);
189
 
198
 
190
         document.body.appendChild(tempElement);
199
         document.body.appendChild(tempElement);
191
-        let style = window.getComputedStyle(tempElement).display;
200
+        const style = window.getComputedStyle(tempElement).display;
201
+
192
         document.body.removeChild(tempElement);
202
         document.body.removeChild(tempElement);
193
 
203
 
194
         return style;
204
         return style;
203
      */
213
      */
204
     setVisibleBySelector(jquerySelector, isVisible) {
214
     setVisibleBySelector(jquerySelector, isVisible) {
205
         if (jquerySelector && jquerySelector.length > 0) {
215
         if (jquerySelector && jquerySelector.length > 0) {
206
-            jquerySelector.css("visibility", isVisible ? "visible" : "hidden");
216
+            jquerySelector.css('visibility', isVisible ? 'visible' : 'hidden');
207
         }
217
         }
208
     },
218
     },
209
 
219
 
264
       */
274
       */
265
     attrsToString(attrs) {
275
     attrsToString(attrs) {
266
         return (
276
         return (
267
-            Object.keys(attrs).map(key => ` ${key}="${attrs[key]}"`).join(' '));
277
+            Object.keys(attrs).map(key => ` ${key}="${attrs[key]}"`)
278
+.join(' '));
268
     },
279
     },
269
 
280
 
270
     /**
281
     /**
275
      * @param {el} The DOM element we'd like to check for visibility
286
      * @param {el} The DOM element we'd like to check for visibility
276
      */
287
      */
277
     isVisible(el) {
288
     isVisible(el) {
278
-        return (el.offsetParent !== null);
289
+        return el.offsetParent !== null;
279
     },
290
     },
280
 
291
 
281
     /**
292
     /**
288
      * element
299
      * element
289
      */
300
      */
290
     animateShowElement(selector, show, hideDelay) {
301
     animateShowElement(selector, show, hideDelay) {
291
-        if(show) {
292
-            if (!selector.is(":visible"))
293
-                selector.css("display", "inline-block");
302
+        if (show) {
303
+            if (!selector.is(':visible')) {
304
+                selector.css('display', 'inline-block');
305
+            }
294
 
306
 
295
             selector.fadeIn(300,
307
             selector.fadeIn(300,
296
-                () => {selector.css({opacity: 1});}
308
+                () => {
309
+                    selector.css({ opacity: 1 });
310
+                }
297
             );
311
             );
298
 
312
 
299
-            if (hideDelay && hideDelay > 0)
313
+            if (hideDelay && hideDelay > 0) {
300
                 setTimeout(
314
                 setTimeout(
301
                     () => {
315
                     () => {
302
                         selector.fadeOut(
316
                         selector.fadeOut(
303
                             300,
317
                             300,
304
-                            () => { selector.css({opacity: 0}); });
318
+                            () => {
319
+                                selector.css({ opacity: 0 });
320
+                            });
305
                     },
321
                     },
306
                     hideDelay);
322
                     hideDelay);
307
-        }
308
-        else {
323
+            }
324
+        } else {
309
             selector.fadeOut(300,
325
             selector.fadeOut(300,
310
-                () => {selector.css({opacity: 0});}
326
+                () => {
327
+                    selector.css({ opacity: 0 });
328
+                }
311
             );
329
             );
312
         }
330
         }
313
     },
331
     },
318
      * @param cssValue the string value we obtain when querying css properties
336
      * @param cssValue the string value we obtain when querying css properties
319
      */
337
      */
320
     parseCssInt(cssValue) {
338
     parseCssInt(cssValue) {
321
-        return parseInt(cssValue) || 0;
339
+        return parseInt(cssValue, 10) || 0;
322
     },
340
     },
323
 
341
 
324
     /**
342
     /**
332
             aLinkElement.attr('href', link);
350
             aLinkElement.attr('href', link);
333
         } else {
351
         } else {
334
             aLinkElement.css({
352
             aLinkElement.css({
335
-                "pointer-events": "none",
336
-                "cursor": "default"
353
+                'pointer-events': 'none',
354
+                'cursor': 'default'
337
             });
355
             });
338
         }
356
         }
339
     },
357
     },

+ 83
- 59
modules/UI/videolayout/Filmstrip.js View File

2
 
2
 
3
 import { setFilmstripVisibility } from '../../../react/features/filmstrip';
3
 import { setFilmstripVisibility } from '../../../react/features/filmstrip';
4
 
4
 
5
-import UIEvents from "../../../service/UI/UIEvents";
6
-import UIUtil from "../util/UIUtil";
5
+import UIEvents from '../../../service/UI/UIEvents';
6
+import UIUtil from '../util/UIUtil';
7
 
7
 
8
 import { sendEvent } from '../../../react/features/analytics';
8
 import { sendEvent } from '../../../react/features/analytics';
9
 
9
 
13
      * @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
13
      * @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
14
      * emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
14
      * emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
15
      */
15
      */
16
-    init (eventEmitter) {
16
+    init(eventEmitter) {
17
         this.iconMenuDownClassName = 'icon-menu-down';
17
         this.iconMenuDownClassName = 'icon-menu-down';
18
         this.iconMenuUpClassName = 'icon-menu-up';
18
         this.iconMenuUpClassName = 'icon-menu-up';
19
         this.filmstripContainerClassName = 'filmstrip';
19
         this.filmstripContainerClassName = 'filmstrip';
33
      * Initializes the filmstrip toolbar.
33
      * Initializes the filmstrip toolbar.
34
      */
34
      */
35
     _initFilmstripToolbar() {
35
     _initFilmstripToolbar() {
36
-        let toolbarContainerHTML = this._generateToolbarHTML();
37
-        let className = this.filmstripContainerClassName;
38
-        let container = document.querySelector(`.${className}`);
36
+        const toolbarContainerHTML = this._generateToolbarHTML();
37
+        const className = this.filmstripContainerClassName;
38
+        const container = document.querySelector(`.${className}`);
39
 
39
 
40
         UIUtil.prependChild(container, toolbarContainerHTML);
40
         UIUtil.prependChild(container, toolbarContainerHTML);
41
 
41
 
42
-        let iconSelector = '#toggleFilmstripButton i';
42
+        const iconSelector = '#toggleFilmstripButton i';
43
+
43
         this.toggleFilmstripIcon = document.querySelector(iconSelector);
44
         this.toggleFilmstripIcon = document.querySelector(iconSelector);
44
     },
45
     },
45
 
46
 
49
      * @private
50
      * @private
50
      */
51
      */
51
     _generateToolbarHTML() {
52
     _generateToolbarHTML() {
52
-        let container = document.createElement('div');
53
-        let isVisible = this.isFilmstripVisible();
53
+        const container = document.createElement('div');
54
+        const isVisible = this.isFilmstripVisible();
55
+
54
         container.className = 'filmstrip__toolbar';
56
         container.className = 'filmstrip__toolbar';
55
         container.innerHTML = `
57
         container.innerHTML = `
56
             <button id="toggleFilmstripButton">
58
             <button id="toggleFilmstripButton">
81
      * @private
83
      * @private
82
      */
84
      */
83
     _registerToggleFilmstripShortcut() {
85
     _registerToggleFilmstripShortcut() {
84
-        let shortcut = 'F';
85
-        let shortcutAttr = 'filmstripPopover';
86
-        let description = 'keyboardShortcuts.toggleFilmstrip';
86
+        const shortcut = 'F';
87
+        const shortcutAttr = 'filmstripPopover';
88
+        const description = 'keyboardShortcuts.toggleFilmstrip';
89
+
87
         // Important:
90
         // Important:
88
         // Firing the event instead of executing toggleFilmstrip method because
91
         // Firing the event instead of executing toggleFilmstrip method because
89
         // it's important to hide the filmstrip by UI.toggleFilmstrip in order
92
         // it's important to hide the filmstrip by UI.toggleFilmstrip in order
90
         // to correctly resize the video area.
93
         // to correctly resize the video area.
91
-        let handler = () => this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
94
+        const handler = () => this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
92
 
95
 
93
         APP.keyboardshortcut.registerShortcut(
96
         APP.keyboardshortcut.registerShortcut(
94
             shortcut,
97
             shortcut,
102
      * Changes classes of icon for showing down state
105
      * Changes classes of icon for showing down state
103
      */
106
      */
104
     showMenuDownIcon() {
107
     showMenuDownIcon() {
105
-        let icon = this.toggleFilmstripIcon;
106
-        if(icon) {
108
+        const icon = this.toggleFilmstripIcon;
109
+
110
+        if (icon) {
107
             icon.classList.add(this.iconMenuDownClassName);
111
             icon.classList.add(this.iconMenuDownClassName);
108
             icon.classList.remove(this.iconMenuUpClassName);
112
             icon.classList.remove(this.iconMenuUpClassName);
109
         }
113
         }
113
      * Changes classes of icon for showing up state
117
      * Changes classes of icon for showing up state
114
      */
118
      */
115
     showMenuUpIcon() {
119
     showMenuUpIcon() {
116
-        let icon = this.toggleFilmstripIcon;
117
-        if(icon) {
120
+        const icon = this.toggleFilmstripIcon;
121
+
122
+        if (icon) {
118
             icon.classList.add(this.iconMenuUpClassName);
123
             icon.classList.add(this.iconMenuUpClassName);
119
             icon.classList.remove(this.iconMenuDownClassName);
124
             icon.classList.remove(this.iconMenuDownClassName);
120
         }
125
         }
137
      */
142
      */
138
     toggleFilmstrip(visible, sendAnalytics = true) {
143
     toggleFilmstrip(visible, sendAnalytics = true) {
139
         const isVisibleDefined = typeof visible === 'boolean';
144
         const isVisibleDefined = typeof visible === 'boolean';
145
+
140
         if (!isVisibleDefined) {
146
         if (!isVisibleDefined) {
147
+            // eslint-disable-next-line no-param-reassign
141
             visible = this.isFilmstripVisible();
148
             visible = this.isFilmstripVisible();
142
         } else if (this.isFilmstripVisible() === visible) {
149
         } else if (this.isFilmstripVisible() === visible) {
143
             return;
150
             return;
145
         if (sendAnalytics) {
152
         if (sendAnalytics) {
146
             sendEvent('toolbar.filmstrip.toggled');
153
             sendEvent('toolbar.filmstrip.toggled');
147
         }
154
         }
148
-        this.filmstrip.toggleClass("hidden");
155
+        this.filmstrip.toggleClass('hidden');
149
 
156
 
150
         if (visible) {
157
         if (visible) {
151
             this.showMenuUpIcon();
158
             this.showMenuUpIcon();
190
         // display should be.
197
         // display should be.
191
         if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
198
         if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
192
             return $(`.${this.filmstripContainerClassName}`).outerHeight();
199
             return $(`.${this.filmstripContainerClassName}`).outerHeight();
193
-        } else {
194
-            return 0;
195
         }
200
         }
201
+
202
+        return 0;
203
+
196
     },
204
     },
197
 
205
 
198
     /**
206
     /**
200
      * @returns {*|{localVideo, remoteVideo}}
208
      * @returns {*|{localVideo, remoteVideo}}
201
      */
209
      */
202
     calculateThumbnailSize() {
210
     calculateThumbnailSize() {
203
-        let availableSizes = this.calculateAvailableSize();
204
-        let width = availableSizes.availableWidth;
205
-        let height = availableSizes.availableHeight;
211
+        const availableSizes = this.calculateAvailableSize();
212
+        const width = availableSizes.availableWidth;
213
+        const height = availableSizes.availableHeight;
206
 
214
 
207
         return this.calculateThumbnailSizeFromAvailable(width, height);
215
         return this.calculateThumbnailSizeFromAvailable(width, height);
208
     },
216
     },
215
      */
223
      */
216
     calculateAvailableSize() {
224
     calculateAvailableSize() {
217
         let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
225
         let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
218
-        let thumbs = this.getThumbs(true);
219
-        let numvids = thumbs.remoteThumbs.length;
226
+        const thumbs = this.getThumbs(true);
227
+        const numvids = thumbs.remoteThumbs.length;
220
 
228
 
221
-        let localVideoContainer = $("#localVideoContainer");
229
+        const localVideoContainer = $('#localVideoContainer');
222
 
230
 
223
         /**
231
         /**
224
          * If the videoAreaAvailableWidth is set we use this one to calculate
232
          * If the videoAreaAvailableWidth is set we use this one to calculate
225
          * the filmstrip width, because we're probably in a state where the
233
          * the filmstrip width, because we're probably in a state where the
226
          * filmstrip size hasn't been updated yet, but it will be.
234
          * filmstrip size hasn't been updated yet, but it will be.
227
          */
235
          */
228
-        let videoAreaAvailableWidth
236
+        const videoAreaAvailableWidth
229
             = UIUtil.getAvailableVideoWidth()
237
             = UIUtil.getAvailableVideoWidth()
230
             - this._getFilmstripExtraPanelsWidth()
238
             - this._getFilmstripExtraPanelsWidth()
231
             - UIUtil.parseCssInt(this.filmstrip.css('right'), 10)
239
             - UIUtil.parseCssInt(this.filmstrip.css('right'), 10)
238
         let availableWidth = videoAreaAvailableWidth;
246
         let availableWidth = videoAreaAvailableWidth;
239
 
247
 
240
         // If local thumb is not hidden
248
         // If local thumb is not hidden
241
-        if(thumbs.localThumb) {
249
+        if (thumbs.localThumb) {
242
             availableWidth = Math.floor(
250
             availableWidth = Math.floor(
243
-                (videoAreaAvailableWidth - (
251
+                videoAreaAvailableWidth - (
244
                     UIUtil.parseCssInt(
252
                     UIUtil.parseCssInt(
245
                         localVideoContainer.css('borderLeftWidth'), 10)
253
                         localVideoContainer.css('borderLeftWidth'), 10)
246
                     + UIUtil.parseCssInt(
254
                     + UIUtil.parseCssInt(
252
                     + UIUtil.parseCssInt(
260
                     + UIUtil.parseCssInt(
253
                         localVideoContainer.css('marginLeft'), 10)
261
                         localVideoContainer.css('marginLeft'), 10)
254
                     + UIUtil.parseCssInt(
262
                     + UIUtil.parseCssInt(
255
-                        localVideoContainer.css('marginRight'), 10)))
263
+                        localVideoContainer.css('marginRight'), 10))
256
             );
264
             );
257
         }
265
         }
258
 
266
 
260
         // filmstrip mode we don't need to calculate further any adjustments
268
         // filmstrip mode we don't need to calculate further any adjustments
261
         // to width based on the number of videos present.
269
         // to width based on the number of videos present.
262
         if (numvids && !interfaceConfig.VERTICAL_FILMSTRIP) {
270
         if (numvids && !interfaceConfig.VERTICAL_FILMSTRIP) {
263
-            let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
271
+            const remoteVideoContainer = thumbs.remoteThumbs.eq(0);
272
+
264
             availableWidth = Math.floor(
273
             availableWidth = Math.floor(
265
-                (videoAreaAvailableWidth - numvids * (
274
+                videoAreaAvailableWidth - (numvids * (
266
                     UIUtil.parseCssInt(
275
                     UIUtil.parseCssInt(
267
                         remoteVideoContainer.css('borderLeftWidth'), 10)
276
                         remoteVideoContainer.css('borderLeftWidth'), 10)
268
                     + UIUtil.parseCssInt(
277
                     + UIUtil.parseCssInt(
278
             );
287
             );
279
         }
288
         }
280
 
289
 
281
-        let maxHeight
290
+        const maxHeight
291
+
282
             // If the MAX_HEIGHT property hasn't been specified
292
             // If the MAX_HEIGHT property hasn't been specified
283
             // we have the static value.
293
             // we have the static value.
284
             = Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
294
             = Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
287
         availableHeight
297
         availableHeight
288
             = Math.min(maxHeight, window.innerHeight - 18);
298
             = Math.min(maxHeight, window.innerHeight - 18);
289
 
299
 
290
-        return { availableWidth, availableHeight };
300
+        return { availableWidth,
301
+            availableHeight };
291
     },
302
     },
292
 
303
 
293
     /**
304
     /**
300
      * @private
311
      * @private
301
      */
312
      */
302
     _getFilmstripExtraPanelsWidth() {
313
     _getFilmstripExtraPanelsWidth() {
303
-        let className = this.filmstripContainerClassName;
314
+        const className = this.filmstripContainerClassName;
304
         let width = 0;
315
         let width = 0;
316
+
305
         $(`.${className}`)
317
         $(`.${className}`)
306
             .children()
318
             .children()
307
-            .each(function () {
319
+            .each(function() {
320
+                /* eslint-disable no-invalid-this */
308
                 if (this.id !== 'remoteVideos') {
321
                 if (this.id !== 'remoteVideos') {
309
                     width += $(this).outerWidth();
322
                     width += $(this).outerWidth();
310
                 }
323
                 }
324
+                /* eslint-enable no-invalid-this */
311
             });
325
             });
326
+
312
         return width;
327
         return width;
313
     },
328
     },
314
 
329
 
362
 
377
 
363
         const remoteThumbsInRow = interfaceConfig.VERTICAL_FILMSTRIP
378
         const remoteThumbsInRow = interfaceConfig.VERTICAL_FILMSTRIP
364
             ? 0 : this.getThumbs(true).remoteThumbs.length;
379
             ? 0 : this.getThumbs(true).remoteThumbs.length;
365
-        const remoteLocalWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO /
366
-            interfaceConfig.LOCAL_THUMBNAIL_RATIO;
367
-        const lW = Math.min(availableWidth /
368
-            (remoteLocalWidthRatio * remoteThumbsInRow + 1), availableHeight *
369
-            interfaceConfig.LOCAL_THUMBNAIL_RATIO);
380
+        const remoteLocalWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO
381
+            / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
382
+        const lW = Math.min(availableWidth
383
+            / ((remoteLocalWidthRatio * remoteThumbsInRow) + 1), availableHeight
384
+            * interfaceConfig.LOCAL_THUMBNAIL_RATIO);
370
         const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
385
         const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
371
 
386
 
372
         const remoteVideoWidth = lW * remoteLocalWidthRatio;
387
         const remoteVideoWidth = lW * remoteLocalWidthRatio;
373
 
388
 
374
         let localVideo;
389
         let localVideo;
390
+
375
         if (interfaceConfig.VERTICAL_FILMSTRIP) {
391
         if (interfaceConfig.VERTICAL_FILMSTRIP) {
376
             localVideo = {
392
             localVideo = {
377
                 thumbWidth: remoteVideoWidth,
393
                 thumbWidth: remoteVideoWidth,
401
      * @param forceUpdate
417
      * @param forceUpdate
402
      * @returns {Promise}
418
      * @returns {Promise}
403
      */
419
      */
420
+    // eslint-disable-next-line max-params
404
     resizeThumbnails(local, remote, animate = false, forceUpdate = false) {
421
     resizeThumbnails(local, remote, animate = false, forceUpdate = false) {
405
         return new Promise(resolve => {
422
         return new Promise(resolve => {
406
-            let thumbs = this.getThumbs(!forceUpdate);
407
-            let promises = [];
423
+            const thumbs = this.getThumbs(!forceUpdate);
424
+            const promises = [];
408
 
425
 
409
-            if(thumbs.localThumb) {
410
-                promises.push(new Promise((resolve) => {
426
+            if (thumbs.localThumb) {
427
+                // eslint-disable-next-line no-shadow
428
+                promises.push(new Promise(resolve => {
411
                     thumbs.localThumb.animate({
429
                     thumbs.localThumb.animate({
412
                         height: local.thumbHeight,
430
                         height: local.thumbHeight,
413
                         width: local.thumbWidth
431
                         width: local.thumbWidth
414
                     }, this._getAnimateOptions(animate, resolve));
432
                     }, this._getAnimateOptions(animate, resolve));
415
                 }));
433
                 }));
416
             }
434
             }
417
-            if(thumbs.remoteThumbs) {
418
-                promises.push(new Promise((resolve) => {
435
+            if (thumbs.remoteThumbs) {
436
+                // eslint-disable-next-line no-shadow
437
+                promises.push(new Promise(resolve => {
419
                     thumbs.remoteThumbs.animate({
438
                     thumbs.remoteThumbs.animate({
420
                         height: remote.thumbHeight,
439
                         height: remote.thumbHeight,
421
                         width: remote.thumbWidth
440
                         width: remote.thumbWidth
422
                     }, this._getAnimateOptions(animate, resolve));
441
                     }, this._getAnimateOptions(animate, resolve));
423
                 }));
442
                 }));
424
             }
443
             }
425
-            promises.push(new Promise((resolve) => {
444
+            // eslint-disable-next-line no-shadow
445
+            promises.push(new Promise(resolve => {
426
                 // Let CSS take care of height in vertical filmstrip mode.
446
                 // Let CSS take care of height in vertical filmstrip mode.
427
                 if (interfaceConfig.VERTICAL_FILMSTRIP) {
447
                 if (interfaceConfig.VERTICAL_FILMSTRIP) {
428
                     $('#filmstripLocalVideo').animate({
448
                     $('#filmstripLocalVideo').animate({
438
             }));
458
             }));
439
 
459
 
440
             promises.push(new Promise(() => {
460
             promises.push(new Promise(() => {
441
-                let { localThumb } = this.getThumbs();
442
-                let height = localThumb ? localThumb.height() : 0;
443
-                let fontSize = UIUtil.getIndicatorFontSize(height);
461
+                const { localThumb } = this.getThumbs();
462
+                const height = localThumb ? localThumb.height() : 0;
463
+                const fontSize = UIUtil.getIndicatorFontSize(height);
464
+
444
                 this.filmstrip.find('.indicator').animate({
465
                 this.filmstrip.find('.indicator').animate({
445
                     fontSize
466
                     fontSize
446
                 }, this._getAnimateOptions(animate, resolve));
467
                 }, this._getAnimateOptions(animate, resolve));
471
 
492
 
472
     /**
493
     /**
473
      * Returns thumbnails of the filmstrip
494
      * Returns thumbnails of the filmstrip
474
-     * @param only_visible
495
+     * @param onlyVisible
475
      * @returns {object} thumbnails
496
      * @returns {object} thumbnails
476
      */
497
      */
477
-    getThumbs(only_visible = false) {
498
+    getThumbs(onlyVisible = false) {
478
         let selector = 'span';
499
         let selector = 'span';
479
-        if (only_visible) {
500
+
501
+        if (onlyVisible) {
480
             selector += ':visible';
502
             selector += ':visible';
481
         }
503
         }
482
 
504
 
483
-        let localThumb = $("#localVideoContainer");
484
-        let remoteThumbs = this.filmstripRemoteVideos.children(selector);
505
+        const localThumb = $('#localVideoContainer');
506
+        const remoteThumbs = this.filmstripRemoteVideos.children(selector);
485
 
507
 
486
         // Exclude the local video container if it has been hidden.
508
         // Exclude the local video container if it has been hidden.
487
-        if (localThumb.hasClass("hidden")) {
509
+        if (localThumb.hasClass('hidden')) {
488
             return { remoteThumbs };
510
             return { remoteThumbs };
489
-        } else {
490
-            return { remoteThumbs, localThumb };
491
         }
511
         }
512
+
513
+        return { remoteThumbs,
514
+            localThumb };
515
+
492
     }
516
     }
493
 };
517
 };
494
 
518
 

+ 11
- 10
modules/UI/videolayout/LargeContainer.js View File

3
  * Base class for all Large containers which we can show.
3
  * Base class for all Large containers which we can show.
4
  */
4
  */
5
 export default class LargeContainer {
5
 export default class LargeContainer {
6
-
6
+    /* eslint-disable no-unused-vars, no-empty-function */
7
     /**
7
     /**
8
      * Show this container.
8
      * Show this container.
9
      * @returns Promise
9
      * @returns Promise
10
      */
10
      */
11
-    show () {
11
+    show() {
12
     }
12
     }
13
 
13
 
14
     /**
14
     /**
15
      * Hide this container.
15
      * Hide this container.
16
      * @returns Promise
16
      * @returns Promise
17
      */
17
      */
18
-    hide () {
18
+    hide() {
19
     }
19
     }
20
 
20
 
21
     /**
21
     /**
24
      * @param {number} containerHeight available height
24
      * @param {number} containerHeight available height
25
      * @param {boolean} animate if container should animate it's resize process
25
      * @param {boolean} animate if container should animate it's resize process
26
      */
26
      */
27
-    // eslint-disable-next-line no-unused-vars
28
-    resize (containerWidth, containerHeight, animate) {
27
+    resize(containerWidth, containerHeight, animate) {
29
     }
28
     }
30
 
29
 
31
     /**
30
     /**
32
      * Handler for "hover in" events.
31
      * Handler for "hover in" events.
33
      */
32
      */
34
-    onHoverIn (e) { // eslint-disable-line no-unused-vars
33
+    onHoverIn(e) {
35
     }
34
     }
36
 
35
 
37
     /**
36
     /**
38
      * Handler for "hover out" events.
37
      * Handler for "hover out" events.
39
      */
38
      */
40
-    onHoverOut (e) { // eslint-disable-line no-unused-vars
39
+    onHoverOut(e) {
41
     }
40
     }
42
 
41
 
43
     /**
42
     /**
46
      * @param {JitsiTrack?} stream new stream
45
      * @param {JitsiTrack?} stream new stream
47
      * @param {string} videoType video type
46
      * @param {string} videoType video type
48
      */
47
      */
49
-    setStream (userID, stream, videoType) {// eslint-disable-line no-unused-vars
48
+    setStream(userID, stream, videoType) {
50
     }
49
     }
51
 
50
 
52
     /**
51
     /**
53
      * Show or hide user avatar.
52
      * Show or hide user avatar.
54
      * @param {boolean} show
53
      * @param {boolean} show
55
      */
54
      */
56
-    showAvatar (show) { // eslint-disable-line no-unused-vars
55
+    showAvatar(show) {
57
     }
56
     }
58
 
57
 
59
     /**
58
     /**
61
      * when the container is on stage.
60
      * when the container is on stage.
62
      * @return {boolean}
61
      * @return {boolean}
63
      */
62
      */
64
-    stayOnStage () {
63
+    stayOnStage() {
65
     }
64
     }
65
+
66
+    /* eslint-enable no-unused-vars, no-empty-function */
66
 }
67
 }

+ 86
- 56
modules/UI/videolayout/LargeVideoManager.js View File

7
 import { PresenceLabel } from '../../../react/features/presence-status';
7
 import { PresenceLabel } from '../../../react/features/presence-status';
8
 /* eslint-enable no-unused-vars */
8
 /* eslint-enable no-unused-vars */
9
 
9
 
10
-const logger = require("jitsi-meet-logger").getLogger(__filename);
10
+const logger = require('jitsi-meet-logger').getLogger(__filename);
11
 
11
 
12
 import {
12
 import {
13
     JitsiParticipantConnectionStatus
13
     JitsiParticipantConnectionStatus
16
     updateKnownLargeVideoResolution
16
     updateKnownLargeVideoResolution
17
 } from '../../../react/features/large-video';
17
 } from '../../../react/features/large-video';
18
 
18
 
19
-import Avatar from "../avatar/Avatar";
20
-import {createDeferred} from '../../util/helpers';
21
-import UIEvents from "../../../service/UI/UIEvents";
22
-import UIUtil from "../util/UIUtil";
23
-import {VideoContainer, VIDEO_CONTAINER_TYPE} from "./VideoContainer";
19
+import Avatar from '../avatar/Avatar';
20
+import { createDeferred } from '../../util/helpers';
21
+import UIEvents from '../../../service/UI/UIEvents';
22
+import UIUtil from '../util/UIUtil';
23
+import { VideoContainer, VIDEO_CONTAINER_TYPE } from './VideoContainer';
24
 
24
 
25
-import AudioLevels from "../audio_levels/AudioLevels";
25
+import AudioLevels from '../audio_levels/AudioLevels';
26
 
26
 
27
 const DESKTOP_CONTAINER_TYPE = 'desktop';
27
 const DESKTOP_CONTAINER_TYPE = 'desktop';
28
+
28
 /**
29
 /**
29
  * The time interval in milliseconds to check the video resolution of the video
30
  * The time interval in milliseconds to check the video resolution of the video
30
  * being displayed.
31
  * being displayed.
49
             || containerType === DESKTOP_CONTAINER_TYPE;
50
             || containerType === DESKTOP_CONTAINER_TYPE;
50
     }
51
     }
51
 
52
 
52
-    constructor (emitter) {
53
+    /**
54
+     *
55
+     */
56
+    constructor(emitter) {
53
         /**
57
         /**
54
          * The map of <tt>LargeContainer</tt>s where the key is the video
58
          * The map of <tt>LargeContainer</tt>s where the key is the video
55
          * container type.
59
          * container type.
59
         this.eventEmitter = emitter;
63
         this.eventEmitter = emitter;
60
 
64
 
61
         this.state = VIDEO_CONTAINER_TYPE;
65
         this.state = VIDEO_CONTAINER_TYPE;
66
+
62
         // FIXME: We are passing resizeContainer as parameter which is calling
67
         // FIXME: We are passing resizeContainer as parameter which is calling
63
         // Container.resize. Probably there's better way to implement this.
68
         // Container.resize. Probably there's better way to implement this.
64
         this.videoContainer = new VideoContainer(
69
         this.videoContainer = new VideoContainer(
125
         this.removePresenceLabel();
130
         this.removePresenceLabel();
126
     }
131
     }
127
 
132
 
128
-    onHoverIn (e) {
133
+    /**
134
+     *
135
+     */
136
+    onHoverIn(e) {
129
         if (!this.state) {
137
         if (!this.state) {
130
             return;
138
             return;
131
         }
139
         }
134
         container.onHoverIn(e);
142
         container.onHoverIn(e);
135
     }
143
     }
136
 
144
 
137
-    onHoverOut (e) {
145
+    /**
146
+     *
147
+     */
148
+    onHoverOut(e) {
138
         if (!this.state) {
149
         if (!this.state) {
139
             return;
150
             return;
140
         }
151
         }
146
     /**
157
     /**
147
      * Called when the media connection has been interrupted.
158
      * Called when the media connection has been interrupted.
148
      */
159
      */
149
-    onVideoInterrupted () {
160
+    onVideoInterrupted() {
150
         this.enableLocalConnectionProblemFilter(true);
161
         this.enableLocalConnectionProblemFilter(true);
151
-        this._setLocalConnectionMessage("connection.RECONNECTING");
162
+        this._setLocalConnectionMessage('connection.RECONNECTING');
163
+
152
         // Show the message only if the video is currently being displayed
164
         // Show the message only if the video is currently being displayed
153
         this.showLocalConnectionMessage(
165
         this.showLocalConnectionMessage(
154
             LargeVideoManager.isVideoContainer(this.state));
166
             LargeVideoManager.isVideoContainer(this.state));
157
     /**
169
     /**
158
      * Called when the media connection has been restored.
170
      * Called when the media connection has been restored.
159
      */
171
      */
160
-    onVideoRestored () {
172
+    onVideoRestored() {
161
         this.enableLocalConnectionProblemFilter(false);
173
         this.enableLocalConnectionProblemFilter(false);
162
         this.showLocalConnectionMessage(false);
174
         this.showLocalConnectionMessage(false);
163
     }
175
     }
164
 
176
 
165
-    get id () {
177
+    /**
178
+     *
179
+     */
180
+    get id() {
166
         const container = this.getCurrentContainer();
181
         const container = this.getCurrentContainer();
182
+
183
+
167
         return container.id;
184
         return container.id;
168
     }
185
     }
169
 
186
 
170
-    scheduleLargeVideoUpdate () {
187
+    /**
188
+     *
189
+     */
190
+    scheduleLargeVideoUpdate() {
171
         if (this.updateInProcess || !this.newStreamData) {
191
         if (this.updateInProcess || !this.newStreamData) {
172
             return;
192
             return;
173
         }
193
         }
175
         this.updateInProcess = true;
195
         this.updateInProcess = true;
176
 
196
 
177
         // Include hide()/fadeOut only if we're switching between users
197
         // Include hide()/fadeOut only if we're switching between users
198
+        // eslint-disable-next-line eqeqeq
178
         const isUserSwitch = this.newStreamData.id != this.id;
199
         const isUserSwitch = this.newStreamData.id != this.id;
179
         const container = this.getCurrentContainer();
200
         const container = this.getCurrentContainer();
180
         const preUpdate = isUserSwitch ? container.hide() : Promise.resolve();
201
         const preUpdate = isUserSwitch ? container.hide() : Promise.resolve();
190
 
211
 
191
             this.newStreamData = null;
212
             this.newStreamData = null;
192
 
213
 
193
-            logger.info("hover in %s", id);
214
+            logger.info('hover in %s', id);
194
             this.state = videoType;
215
             this.state = videoType;
216
+            // eslint-disable-next-line no-shadow
195
             const container = this.getCurrentContainer();
217
             const container = this.getCurrentContainer();
218
+
196
             container.setStream(id, stream, videoType);
219
             container.setStream(id, stream, videoType);
197
 
220
 
198
             // change the avatar url on large
221
             // change the avatar url on large
215
                                 === JitsiParticipantConnectionStatus.ACTIVE
238
                                 === JitsiParticipantConnectionStatus.ACTIVE
216
                         || wasUsersImageCached);
239
                         || wasUsersImageCached);
217
 
240
 
218
-            let showAvatar
241
+            const showAvatar
219
                 = isVideoContainer
242
                 = isVideoContainer
220
                     && (APP.conference.isAudioOnly() || !isVideoRenderable);
243
                     && (APP.conference.isAudioOnly() || !isVideoRenderable);
221
 
244
 
225
             // but we still should show watermark
248
             // but we still should show watermark
226
             if (showAvatar) {
249
             if (showAvatar) {
227
                 this.showWatermark(true);
250
                 this.showWatermark(true);
251
+
228
                 // If the intention of this switch is to show the avatar
252
                 // If the intention of this switch is to show the avatar
229
                 // we need to make sure that the video is hidden
253
                 // we need to make sure that the video is hidden
230
                 promise = container.hide();
254
                 promise = container.hide();
246
             let messageKey = null;
270
             let messageKey = null;
247
 
271
 
248
             if (isConnectionInterrupted) {
272
             if (isConnectionInterrupted) {
249
-                messageKey = "connection.USER_CONNECTION_INTERRUPTED";
273
+                messageKey = 'connection.USER_CONNECTION_INTERRUPTED';
250
             } else if (connectionStatus
274
             } else if (connectionStatus
251
                     === JitsiParticipantConnectionStatus.INACTIVE) {
275
                     === JitsiParticipantConnectionStatus.INACTIVE) {
252
-                messageKey = "connection.LOW_BANDWIDTH";
276
+                messageKey = 'connection.LOW_BANDWIDTH';
253
             }
277
             }
254
 
278
 
255
             // Make sure no notification about remote failure is shown as
279
             // Make sure no notification about remote failure is shown as
302
         this.videoContainer.showRemoteConnectionProblemIndicator(
326
         this.videoContainer.showRemoteConnectionProblemIndicator(
303
             showProblemsIndication);
327
             showProblemsIndication);
304
 
328
 
305
-        if (!messageKey) {
306
-            // Hide the message
307
-            this.showRemoteConnectionMessage(false);
308
-        } else {
329
+        if (messageKey) {
309
             // Get user's display name
330
             // Get user's display name
310
-            let displayName
331
+            const displayName
311
                 = APP.conference.getParticipantDisplayName(id);
332
                 = APP.conference.getParticipantDisplayName(id);
333
+
312
             this._setRemoteConnectionMessage(
334
             this._setRemoteConnectionMessage(
313
                 messageKey,
335
                 messageKey,
314
-                { displayName: displayName });
336
+                { displayName });
315
 
337
 
316
             // Show it now only if the VideoContainer is on top
338
             // Show it now only if the VideoContainer is on top
317
             this.showRemoteConnectionMessage(
339
             this.showRemoteConnectionMessage(
318
                 LargeVideoManager.isVideoContainer(this.state));
340
                 LargeVideoManager.isVideoContainer(this.state));
341
+        } else {
342
+            // Hide the message
343
+            this.showRemoteConnectionMessage(false);
319
         }
344
         }
345
+
320
     }
346
     }
321
 
347
 
322
     /**
348
     /**
327
      * @param {string?} videoType new video type
353
      * @param {string?} videoType new video type
328
      * @returns {Promise}
354
      * @returns {Promise}
329
      */
355
      */
330
-    updateLargeVideo (userID, stream, videoType) {
356
+    updateLargeVideo(userID, stream, videoType) {
331
         if (this.newStreamData) {
357
         if (this.newStreamData) {
332
             this.newStreamData.reject();
358
             this.newStreamData.reject();
333
         }
359
         }
345
     /**
371
     /**
346
      * Update container size.
372
      * Update container size.
347
      */
373
      */
348
-    updateContainerSize () {
374
+    updateContainerSize() {
349
         this.width = UIUtil.getAvailableVideoWidth();
375
         this.width = UIUtil.getAvailableVideoWidth();
350
         this.height = window.innerHeight;
376
         this.height = window.innerHeight;
351
     }
377
     }
355
      * @param {string} type type of container which should be resized.
381
      * @param {string} type type of container which should be resized.
356
      * @param {boolean} [animate=false] if resize process should be animated.
382
      * @param {boolean} [animate=false] if resize process should be animated.
357
      */
383
      */
358
-    resizeContainer (type, animate = false) {
359
-        let container = this.getContainer(type);
384
+    resizeContainer(type, animate = false) {
385
+        const container = this.getContainer(type);
386
+
360
         container.resize(this.width, this.height, animate);
387
         container.resize(this.width, this.height, animate);
361
     }
388
     }
362
 
389
 
364
      * Resize all Large containers.
391
      * Resize all Large containers.
365
      * @param {boolean} animate if resize process should be animated.
392
      * @param {boolean} animate if resize process should be animated.
366
      */
393
      */
367
-    resize (animate) {
394
+    resize(animate) {
368
         // resize all containers
395
         // resize all containers
369
         Object.keys(this.containers)
396
         Object.keys(this.containers)
370
             .forEach(type => this.resizeContainer(type, animate));
397
             .forEach(type => this.resizeContainer(type, animate));
384
      *
411
      *
385
      * @param enable <tt>true</tt> to enable, <tt>false</tt> to disable
412
      * @param enable <tt>true</tt> to enable, <tt>false</tt> to disable
386
      */
413
      */
387
-    enableLocalConnectionProblemFilter (enable) {
414
+    enableLocalConnectionProblemFilter(enable) {
388
         this.videoContainer.enableLocalConnectionProblemFilter(enable);
415
         this.videoContainer.enableLocalConnectionProblemFilter(enable);
389
     }
416
     }
390
 
417
 
391
     /**
418
     /**
392
      * Updates the src of the dominant speaker avatar
419
      * Updates the src of the dominant speaker avatar
393
      */
420
      */
394
-    updateAvatar (avatarUrl) {
395
-        $("#dominantSpeakerAvatar").attr('src', avatarUrl);
421
+    updateAvatar(avatarUrl) {
422
+        $('#dominantSpeakerAvatar').attr('src', avatarUrl);
396
     }
423
     }
397
 
424
 
398
     /**
425
     /**
400
      *
427
      *
401
      * @param lvl the new audio level to set
428
      * @param lvl the new audio level to set
402
      */
429
      */
403
-    updateLargeVideoAudioLevel (lvl) {
404
-        AudioLevels.updateLargeVideoAudioLevel("dominantSpeaker", lvl);
430
+    updateLargeVideoAudioLevel(lvl) {
431
+        AudioLevels.updateLargeVideoAudioLevel('dominantSpeaker', lvl);
405
     }
432
     }
406
 
433
 
407
     /**
434
     /**
418
 
445
 
419
         if (isConnectionMessageVisible) {
446
         if (isConnectionMessageVisible) {
420
             this.removePresenceLabel();
447
             this.removePresenceLabel();
448
+
421
             return;
449
             return;
422
         }
450
         }
423
 
451
 
424
         const presenceLabelContainer = $('#remotePresenceMessage');
452
         const presenceLabelContainer = $('#remotePresenceMessage');
425
 
453
 
426
         if (presenceLabelContainer.length) {
454
         if (presenceLabelContainer.length) {
427
-            /* jshint ignore:start */
428
             ReactDOM.render(
455
             ReactDOM.render(
429
                 <Provider store = { APP.store }>
456
                 <Provider store = { APP.store }>
430
                     <PresenceLabel participantID = { id } />
457
                     <PresenceLabel participantID = { id } />
431
                 </Provider>,
458
                 </Provider>,
432
                 presenceLabelContainer.get(0));
459
                 presenceLabelContainer.get(0));
433
-            /* jshint ignore:end */
434
         }
460
         }
435
     }
461
     }
436
 
462
 
443
         const presenceLabelContainer = $('#remotePresenceMessage');
469
         const presenceLabelContainer = $('#remotePresenceMessage');
444
 
470
 
445
         if (presenceLabelContainer.length) {
471
         if (presenceLabelContainer.length) {
446
-            /* jshint ignore:start */
447
             ReactDOM.unmountComponentAtNode(presenceLabelContainer.get(0));
472
             ReactDOM.unmountComponentAtNode(presenceLabelContainer.get(0));
448
-            /* jshint ignore:end */
449
         }
473
         }
450
     }
474
     }
451
 
475
 
453
      * Show or hide watermark.
477
      * Show or hide watermark.
454
      * @param {boolean} show
478
      * @param {boolean} show
455
      */
479
      */
456
-    showWatermark (show) {
480
+    showWatermark(show) {
457
         $('.watermark').css('visibility', show ? 'visible' : 'hidden');
481
         $('.watermark').css('visibility', show ? 'visible' : 'hidden');
458
     }
482
     }
459
 
483
 
463
      * displayed or not. If missing the condition will be based on the value
487
      * displayed or not. If missing the condition will be based on the value
464
      * obtained from {@link APP.conference.isConnectionInterrupted}.
488
      * obtained from {@link APP.conference.isConnectionInterrupted}.
465
      */
489
      */
466
-    showLocalConnectionMessage (show) {
490
+    showLocalConnectionMessage(show) {
467
         if (typeof show !== 'boolean') {
491
         if (typeof show !== 'boolean') {
492
+            // eslint-disable-next-line no-param-reassign
468
             show = APP.conference.isConnectionInterrupted();
493
             show = APP.conference.isConnectionInterrupted();
469
         }
494
         }
470
 
495
 
471
-        let id = 'localConnectionMessage';
496
+        const id = 'localConnectionMessage';
472
 
497
 
473
         UIUtil.setVisible(id, show);
498
         UIUtil.setVisible(id, show);
474
 
499
 
489
      * obtained form "APP.conference" and the message will be displayed if
514
      * obtained form "APP.conference" and the message will be displayed if
490
      * the user's connection is either interrupted or inactive.
515
      * the user's connection is either interrupted or inactive.
491
      */
516
      */
492
-    showRemoteConnectionMessage (show) {
517
+    showRemoteConnectionMessage(show) {
493
         if (typeof show !== 'boolean') {
518
         if (typeof show !== 'boolean') {
494
             const connStatus
519
             const connStatus
495
                 = APP.conference.getParticipantConnectionStatus(this.id);
520
                 = APP.conference.getParticipantConnectionStatus(this.id);
496
 
521
 
522
+            // eslint-disable-next-line no-param-reassign
497
             show = !APP.conference.isLocalId(this.id)
523
             show = !APP.conference.isLocalId(this.id)
498
                 && (connStatus === JitsiParticipantConnectionStatus.INTERRUPTED
524
                 && (connStatus === JitsiParticipantConnectionStatus.INTERRUPTED
499
                     || connStatus
525
                     || connStatus
501
         }
527
         }
502
 
528
 
503
         if (show) {
529
         if (show) {
504
-            $('#remoteConnectionMessage').css({display: "block"});
530
+            $('#remoteConnectionMessage').css({ display: 'block' });
531
+
505
             // 'videoConnectionMessage' message conflicts with 'avatarMessage',
532
             // 'videoConnectionMessage' message conflicts with 'avatarMessage',
506
             // so it must be hidden
533
             // so it must be hidden
507
             this.showLocalConnectionMessage(false);
534
             this.showLocalConnectionMessage(false);
520
      *
547
      *
521
      * @private
548
      * @private
522
      */
549
      */
523
-    _setRemoteConnectionMessage (msgKey, msgOptions) {
550
+    _setRemoteConnectionMessage(msgKey, msgOptions) {
524
         if (msgKey) {
551
         if (msgKey) {
525
             $('#remoteConnectionMessage')
552
             $('#remoteConnectionMessage')
526
-                .attr("data-i18n", msgKey)
527
-                .attr("data-i18n-options", JSON.stringify(msgOptions));
553
+                .attr('data-i18n', msgKey)
554
+                .attr('data-i18n-options', JSON.stringify(msgOptions));
528
             APP.translation.translateElement(
555
             APP.translation.translateElement(
529
                 $('#remoteConnectionMessage'), msgOptions);
556
                 $('#remoteConnectionMessage'), msgOptions);
530
         }
557
         }
539
      *
566
      *
540
      * @private
567
      * @private
541
      */
568
      */
542
-    _setLocalConnectionMessage (msgKey) {
569
+    _setLocalConnectionMessage(msgKey) {
543
         $('#localConnectionMessage')
570
         $('#localConnectionMessage')
544
-            .attr("data-i18n", msgKey);
571
+            .attr('data-i18n', msgKey);
545
         APP.translation.translateElement($('#localConnectionMessage'));
572
         APP.translation.translateElement($('#localConnectionMessage'));
546
     }
573
     }
547
 
574
 
550
      * @param {string} type container type
577
      * @param {string} type container type
551
      * @param {LargeContainer} container container to add.
578
      * @param {LargeContainer} container container to add.
552
      */
579
      */
553
-    addContainer (type, container) {
580
+    addContainer(type, container) {
554
         if (this.containers[type]) {
581
         if (this.containers[type]) {
555
             throw new Error(`container of type ${type} already exist`);
582
             throw new Error(`container of type ${type} already exist`);
556
         }
583
         }
564
      * @param {string} type container type.
591
      * @param {string} type container type.
565
      * @returns {LargeContainer}
592
      * @returns {LargeContainer}
566
      */
593
      */
567
-    getContainer (type) {
568
-        let container = this.containers[type];
594
+    getContainer(type) {
595
+        const container = this.containers[type];
569
 
596
 
570
         if (!container) {
597
         if (!container) {
571
             throw new Error(`container of type ${type} doesn't exist`);
598
             throw new Error(`container of type ${type} doesn't exist`);
598
      * Remove Large container of specified type.
625
      * Remove Large container of specified type.
599
      * @param {string} type container type.
626
      * @param {string} type container type.
600
      */
627
      */
601
-    removeContainer (type) {
628
+    removeContainer(type) {
602
         if (!this.containers[type]) {
629
         if (!this.containers[type]) {
603
             throw new Error(`container of type ${type} doesn't exist`);
630
             throw new Error(`container of type ${type} doesn't exist`);
604
         }
631
         }
612
      * @param {string} type container type.
639
      * @param {string} type container type.
613
      * @returns {Promise}
640
      * @returns {Promise}
614
      */
641
      */
615
-    showContainer (type) {
642
+    showContainer(type) {
616
         if (this.state === type) {
643
         if (this.state === type) {
617
             return Promise.resolve();
644
             return Promise.resolve();
618
         }
645
         }
619
 
646
 
620
-        let oldContainer = this.containers[this.state];
647
+        const oldContainer = this.containers[this.state];
648
+
621
         // FIXME when video is being replaced with other content we need to hide
649
         // FIXME when video is being replaced with other content we need to hide
622
         // companion icons/messages. It would be best if the container would
650
         // companion icons/messages. It would be best if the container would
623
         // be taking care of it by itself, but that is a bigger refactoring
651
         // be taking care of it by itself, but that is a bigger refactoring
652
+
624
         if (LargeVideoManager.isVideoContainer(this.state)) {
653
         if (LargeVideoManager.isVideoContainer(this.state)) {
625
             this.showWatermark(false);
654
             this.showWatermark(false);
626
             this.showLocalConnectionMessage(false);
655
             this.showLocalConnectionMessage(false);
629
         oldContainer.hide();
658
         oldContainer.hide();
630
 
659
 
631
         this.state = type;
660
         this.state = type;
632
-        let container = this.getContainer(type);
661
+        const container = this.getContainer(type);
633
 
662
 
634
         return container.show().then(() => {
663
         return container.show().then(() => {
635
             if (LargeVideoManager.isVideoContainer(type)) {
664
             if (LargeVideoManager.isVideoContainer(type)) {
638
                 // the container would be taking care of it by itself, but that
667
                 // the container would be taking care of it by itself, but that
639
                 // is a bigger refactoring
668
                 // is a bigger refactoring
640
                 this.showWatermark(true);
669
                 this.showWatermark(true);
670
+
641
                 // "avatar" and "video connection" can not be displayed both
671
                 // "avatar" and "video connection" can not be displayed both
642
                 // at the same time, but the latter is of higher priority and it
672
                 // at the same time, but the latter is of higher priority and it
643
                 // will hide the avatar one if will be displayed.
673
                 // will hide the avatar one if will be displayed.

+ 48
- 38
modules/UI/videolayout/LocalVideo.js View File

9
 import { VideoTrack } from '../../../react/features/base/media';
9
 import { VideoTrack } from '../../../react/features/base/media';
10
 /* eslint-enable no-unused-vars */
10
 /* eslint-enable no-unused-vars */
11
 
11
 
12
-const logger = require("jitsi-meet-logger").getLogger(__filename);
12
+const logger = require('jitsi-meet-logger').getLogger(__filename);
13
 
13
 
14
-import UIEvents from "../../../service/UI/UIEvents";
15
-import SmallVideo from "./SmallVideo";
14
+import UIEvents from '../../../service/UI/UIEvents';
15
+import SmallVideo from './SmallVideo';
16
 
16
 
17
+/**
18
+ *
19
+ */
17
 function LocalVideo(VideoLayout, emitter) {
20
 function LocalVideo(VideoLayout, emitter) {
18
-    this.videoSpanId = "localVideoContainer";
21
+    this.videoSpanId = 'localVideoContainer';
19
 
22
 
20
     this.container = this.createContainer();
23
     this.container = this.createContainer();
21
     this.$container = $(this.container);
24
     this.$container = $(this.container);
22
-    $("#filmstripLocalVideo").append(this.container);
25
+    $('#filmstripLocalVideo').append(this.container);
23
 
26
 
24
     this.localVideoId = null;
27
     this.localVideoId = null;
25
     this.bindHoverHandler();
28
     this.bindHoverHandler();
26
-    if(config.enableLocalVideoFlip)
29
+    if (config.enableLocalVideoFlip) {
27
         this._buildContextMenu();
30
         this._buildContextMenu();
31
+    }
28
     this.isLocal = true;
32
     this.isLocal = true;
29
     this.emitter = emitter;
33
     this.emitter = emitter;
30
     this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP
34
     this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP
31
         ? 'left top' : 'top center';
35
         ? 'left top' : 'top center';
32
 
36
 
33
     Object.defineProperty(this, 'id', {
37
     Object.defineProperty(this, 'id', {
34
-        get: function () {
38
+        get() {
35
             return APP.conference.getMyUserId();
39
             return APP.conference.getMyUserId();
36
         }
40
         }
37
     });
41
     });
49
 LocalVideo.prototype = Object.create(SmallVideo.prototype);
53
 LocalVideo.prototype = Object.create(SmallVideo.prototype);
50
 LocalVideo.prototype.constructor = LocalVideo;
54
 LocalVideo.prototype.constructor = LocalVideo;
51
 
55
 
52
-LocalVideo.prototype.createContainer = function () {
56
+LocalVideo.prototype.createContainer = function() {
53
     const containerSpan = document.createElement('span');
57
     const containerSpan = document.createElement('span');
58
+
54
     containerSpan.classList.add('videocontainer');
59
     containerSpan.classList.add('videocontainer');
55
     containerSpan.id = this.videoSpanId;
60
     containerSpan.id = this.videoSpanId;
56
 
61
 
72
 LocalVideo.prototype.setDisplayName = function(displayName) {
77
 LocalVideo.prototype.setDisplayName = function(displayName) {
73
     if (!this.container) {
78
     if (!this.container) {
74
         logger.warn(
79
         logger.warn(
75
-                "Unable to set displayName - " + this.videoSpanId +
76
-                " does not exist");
80
+                `Unable to set displayName - ${this.videoSpanId
81
+                } does not exist`);
82
+
77
         return;
83
         return;
78
     }
84
     }
79
 
85
 
80
     this.updateDisplayName({
86
     this.updateDisplayName({
81
         allowEditing: true,
87
         allowEditing: true,
82
-        displayName: displayName,
88
+        displayName,
83
         displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
89
         displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
84
         elementID: 'localDisplayName',
90
         elementID: 'localDisplayName',
85
         participantID: this.id
91
         participantID: this.id
86
     });
92
     });
87
 };
93
 };
88
 
94
 
89
-LocalVideo.prototype.changeVideo = function (stream) {
95
+LocalVideo.prototype.changeVideo = function(stream) {
90
     this.videoStream = stream;
96
     this.videoStream = stream;
91
 
97
 
92
-    let localVideoClick = (event) => {
98
+    const localVideoClick = event => {
93
         // TODO Checking the classes is a workround to allow events to bubble
99
         // TODO Checking the classes is a workround to allow events to bubble
94
         // into the DisplayName component if it was clicked. React's synthetic
100
         // into the DisplayName component if it was clicked. React's synthetic
95
         // events will fire after jQuery handlers execute, so stop propogation
101
         // events will fire after jQuery handlers execute, so stop propogation
125
     this.$container.off('click');
131
     this.$container.off('click');
126
     this.$container.on('click', localVideoClick);
132
     this.$container.on('click', localVideoClick);
127
 
133
 
128
-    this.localVideoId = 'localVideo_' + stream.getId();
134
+    this.localVideoId = `localVideo_${stream.getId()}`;
129
 
135
 
130
-    var localVideoContainer = document.getElementById('localVideoWrapper');
136
+    const localVideoContainer = document.getElementById('localVideoWrapper');
131
 
137
 
132
-    /* jshint ignore:start */
133
     ReactDOM.render(
138
     ReactDOM.render(
134
         <Provider store = { APP.store }>
139
         <Provider store = { APP.store }>
135
             <VideoTrack
140
             <VideoTrack
138
         </Provider>,
143
         </Provider>,
139
         localVideoContainer
144
         localVideoContainer
140
     );
145
     );
141
-    /* jshint ignore:end */
142
 
146
 
143
-    let isVideo = stream.videoType != "desktop";
147
+    // eslint-disable-next-line eqeqeq
148
+    const isVideo = stream.videoType != 'desktop';
149
+
144
     this._enableDisableContextMenu(isVideo);
150
     this._enableDisableContextMenu(isVideo);
145
-    this.setFlipX(isVideo? APP.settings.getLocalFlipX() : false);
151
+    this.setFlipX(isVideo ? APP.settings.getLocalFlipX() : false);
152
+
153
+    const endedHandler = () => {
146
 
154
 
147
-    let endedHandler = () => {
148
         // Only remove if there is no video and not a transition state.
155
         // Only remove if there is no video and not a transition state.
149
         // Previous non-react logic created a new video element with each track
156
         // Previous non-react logic created a new video element with each track
150
         // removal whereas react reuses the video component so it could be the
157
         // removal whereas react reuses the video component so it could be the
160
         }
167
         }
161
         stream.off(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
168
         stream.off(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
162
     };
169
     };
170
+
163
     stream.on(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
171
     stream.on(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
164
 };
172
 };
165
 
173
 
172
 
180
 
173
     // We toggle the hidden class as an indication to other interested parties
181
     // We toggle the hidden class as an indication to other interested parties
174
     // that this container has been hidden on purpose.
182
     // that this container has been hidden on purpose.
175
-    this.$container.toggleClass("hidden");
183
+    this.$container.toggleClass('hidden');
176
 
184
 
177
     // We still show/hide it as we need to overwrite the style property if we
185
     // We still show/hide it as we need to overwrite the style property if we
178
     // want our action to take effect. Toggling the display property through
186
     // want our action to take effect. Toggling the display property through
179
     // the above css class didn't succeed in overwriting the style.
187
     // the above css class didn't succeed in overwriting the style.
180
     if (visible) {
188
     if (visible) {
181
         this.$container.show();
189
         this.$container.show();
182
-    }
183
-    else {
190
+    } else {
184
         this.$container.hide();
191
         this.$container.hide();
185
     }
192
     }
186
 };
193
 };
189
  * Sets the flipX state of the video.
196
  * Sets the flipX state of the video.
190
  * @param val {boolean} true for flipped otherwise false;
197
  * @param val {boolean} true for flipped otherwise false;
191
  */
198
  */
192
-LocalVideo.prototype.setFlipX = function (val) {
199
+LocalVideo.prototype.setFlipX = function(val) {
193
     this.emitter.emit(UIEvents.LOCAL_FLIPX_CHANGED, val);
200
     this.emitter.emit(UIEvents.LOCAL_FLIPX_CHANGED, val);
194
-    if(!this.localVideoId)
201
+    if (!this.localVideoId) {
195
         return;
202
         return;
196
-    if(val) {
197
-        this.selectVideoElement().addClass("flipVideoX");
203
+    }
204
+    if (val) {
205
+        this.selectVideoElement().addClass('flipVideoX');
198
     } else {
206
     } else {
199
-        this.selectVideoElement().removeClass("flipVideoX");
207
+        this.selectVideoElement().removeClass('flipVideoX');
200
     }
208
     }
201
 };
209
 };
202
 
210
 
203
 /**
211
 /**
204
  * Builds the context menu for the local video.
212
  * Builds the context menu for the local video.
205
  */
213
  */
206
-LocalVideo.prototype._buildContextMenu = function () {
214
+LocalVideo.prototype._buildContextMenu = function() {
207
     $.contextMenu({
215
     $.contextMenu({
208
-        selector: '#' + this.videoSpanId,
216
+        selector: `#${this.videoSpanId}`,
209
         zIndex: 10000,
217
         zIndex: 10000,
210
         items: {
218
         items: {
211
             flip: {
219
             flip: {
212
-                name: "Flip",
220
+                name: 'Flip',
213
                 callback: () => {
221
                 callback: () => {
214
-                    let val = !APP.settings.getLocalFlipX();
222
+                    const val = !APP.settings.getLocalFlipX();
223
+
215
                     this.setFlipX(val);
224
                     this.setFlipX(val);
216
                     APP.settings.setLocalFlipX(val);
225
                     APP.settings.setLocalFlipX(val);
217
                 }
226
                 }
218
             }
227
             }
219
         },
228
         },
220
         events: {
229
         events: {
221
-            show : function(options){
222
-                options.items.flip.name =
223
-                    APP.translation.generateTranslationHTML(
224
-                        "videothumbnail.flip");
230
+            show(options) {
231
+                options.items.flip.name
232
+                    = APP.translation.generateTranslationHTML(
233
+                        'videothumbnail.flip');
225
             }
234
             }
226
         }
235
         }
227
     });
236
     });
231
  * Enables or disables the context menu for the local video.
240
  * Enables or disables the context menu for the local video.
232
  * @param enable {boolean} true for enable, false for disable
241
  * @param enable {boolean} true for enable, false for disable
233
  */
242
  */
234
-LocalVideo.prototype._enableDisableContextMenu = function (enable) {
235
-    if(this.$container.contextMenu)
243
+LocalVideo.prototype._enableDisableContextMenu = function(enable) {
244
+    if (this.$container.contextMenu) {
236
         this.$container.contextMenu(enable);
245
         this.$container.contextMenu(enable);
246
+    }
237
 };
247
 };
238
 
248
 
239
 export default LocalVideo;
249
 export default LocalVideo;

+ 97
- 74
modules/UI/videolayout/RemoteVideo.js View File

18
 } from '../../../react/features/remote-video-menu';
18
 } from '../../../react/features/remote-video-menu';
19
 /* eslint-enable no-unused-vars */
19
 /* eslint-enable no-unused-vars */
20
 
20
 
21
-const logger = require("jitsi-meet-logger").getLogger(__filename);
21
+const logger = require('jitsi-meet-logger').getLogger(__filename);
22
 
22
 
23
 
23
 
24
-import SmallVideo from "./SmallVideo";
25
-import UIUtils from "../util/UIUtil";
24
+import SmallVideo from './SmallVideo';
25
+import UIUtils from '../util/UIUtil';
26
 
26
 
27
 /**
27
 /**
28
  * Creates new instance of the <tt>RemoteVideo</tt>.
28
  * Creates new instance of the <tt>RemoteVideo</tt>.
52
     this.isLocal = false;
52
     this.isLocal = false;
53
     this.popupMenuIsHovered = false;
53
     this.popupMenuIsHovered = false;
54
     this._isRemoteControlSessionActive = false;
54
     this._isRemoteControlSessionActive = false;
55
+
55
     /**
56
     /**
56
      * The flag is set to <tt>true</tt> after the 'onplay' event has been
57
      * The flag is set to <tt>true</tt> after the 'onplay' event has been
57
      * triggered on the current video element. It goes back to <tt>false</tt>
58
      * triggered on the current video element. It goes back to <tt>false</tt>
60
      * @type {boolean}
61
      * @type {boolean}
61
      */
62
      */
62
     this.wasVideoPlayed = false;
63
     this.wasVideoPlayed = false;
64
+
63
     /**
65
     /**
64
      * The flag is set to <tt>true</tt> if remote participant's video gets muted
66
      * The flag is set to <tt>true</tt> if remote participant's video gets muted
65
      * during his media connection disruption. This is to prevent black video
67
      * during his media connection disruption. This is to prevent black video
107
  * @private
109
  * @private
108
  * NOTE: extends SmallVideo's method
110
  * NOTE: extends SmallVideo's method
109
  */
111
  */
110
-RemoteVideo.prototype._isHovered = function () {
111
-    let isHovered = SmallVideo.prototype._isHovered.call(this)
112
+RemoteVideo.prototype._isHovered = function() {
113
+    const isHovered = SmallVideo.prototype._isHovered.call(this)
112
         || this.popupMenuIsHovered;
114
         || this.popupMenuIsHovered;
115
+
116
+
113
     return isHovered;
117
     return isHovered;
114
 };
118
 };
115
 
119
 
119
  * @returns {Element|*} the constructed element, containing popup menu items
123
  * @returns {Element|*} the constructed element, containing popup menu items
120
  * @private
124
  * @private
121
  */
125
  */
122
-RemoteVideo.prototype._generatePopupContent = function () {
126
+RemoteVideo.prototype._generatePopupContent = function() {
123
     if (interfaceConfig.filmStripOnly) {
127
     if (interfaceConfig.filmStripOnly) {
124
         return;
128
         return;
125
     }
129
     }
139
         && ((!APP.remoteControl.active && !this._isRemoteControlSessionActive)
143
         && ((!APP.remoteControl.active && !this._isRemoteControlSessionActive)
140
             || APP.remoteControl.controller.activeParticipant === this.id)) {
144
             || APP.remoteControl.controller.activeParticipant === this.id)) {
141
         if (controller.getRequestedParticipant() === this.id) {
145
         if (controller.getRequestedParticipant() === this.id) {
142
-            onRemoteControlToggle = () => {};
143
             remoteControlState = REMOTE_CONTROL_MENU_STATES.REQUESTING;
146
             remoteControlState = REMOTE_CONTROL_MENU_STATES.REQUESTING;
144
-        } else if (!controller.isStarted()) {
145
-            onRemoteControlToggle = this._requestRemoteControlPermissions;
146
-            remoteControlState = REMOTE_CONTROL_MENU_STATES.NOT_STARTED;
147
-        } else {
147
+        } else if (controller.isStarted()) {
148
             onRemoteControlToggle = this._stopRemoteControl;
148
             onRemoteControlToggle = this._stopRemoteControl;
149
             remoteControlState = REMOTE_CONTROL_MENU_STATES.STARTED;
149
             remoteControlState = REMOTE_CONTROL_MENU_STATES.STARTED;
150
+        } else {
151
+            onRemoteControlToggle = this._requestRemoteControlPermissions;
152
+            remoteControlState = REMOTE_CONTROL_MENU_STATES.NOT_STARTED;
150
         }
153
         }
151
     }
154
     }
152
 
155
 
161
     const { isModerator } = APP.conference;
164
     const { isModerator } = APP.conference;
162
     const participantID = this.id;
165
     const participantID = this.id;
163
 
166
 
164
-    /* jshint ignore:start */
165
     ReactDOM.render(
167
     ReactDOM.render(
166
         <Provider store = { APP.store }>
168
         <Provider store = { APP.store }>
167
             <I18nextProvider i18n = { i18next }>
169
             <I18nextProvider i18n = { i18next }>
169
                     initialVolumeValue = { initialVolumeValue }
171
                     initialVolumeValue = { initialVolumeValue }
170
                     isAudioMuted = { this.isAudioMuted }
172
                     isAudioMuted = { this.isAudioMuted }
171
                     isModerator = { isModerator }
173
                     isModerator = { isModerator }
172
-                    onMenuDisplay = { this._onRemoteVideoMenuDisplay.bind(this) }
174
+                    onMenuDisplay = {this._onRemoteVideoMenuDisplay.bind(this)}
173
                     onRemoteControlToggle = { onRemoteControlToggle }
175
                     onRemoteControlToggle = { onRemoteControlToggle }
174
                     onVolumeChange = { onVolumeChange }
176
                     onVolumeChange = { onVolumeChange }
175
                     participantID = { participantID }
177
                     participantID = { participantID }
177
             </I18nextProvider>
179
             </I18nextProvider>
178
         </Provider>,
180
         </Provider>,
179
         remoteVideoMenuContainer);
181
         remoteVideoMenuContainer);
180
-    /* jshint ignore:end */
181
 };
182
 };
182
 
183
 
183
-RemoteVideo.prototype._onRemoteVideoMenuDisplay = function () {
184
+RemoteVideo.prototype._onRemoteVideoMenuDisplay = function() {
184
     this.updateRemoteVideoMenu();
185
     this.updateRemoteVideoMenu();
185
 };
186
 };
186
 
187
 
201
  * @param {boolean} isSupported
202
  * @param {boolean} isSupported
202
  */
203
  */
203
 RemoteVideo.prototype.setRemoteControlSupport = function(isSupported = false) {
204
 RemoteVideo.prototype.setRemoteControlSupport = function(isSupported = false) {
204
-    if(this._supportsRemoteControl === isSupported) {
205
+    if (this._supportsRemoteControl === isSupported) {
205
         return;
206
         return;
206
     }
207
     }
207
     this._supportsRemoteControl = isSupported;
208
     this._supportsRemoteControl = isSupported;
211
 /**
212
 /**
212
  * Requests permissions for remote control session.
213
  * Requests permissions for remote control session.
213
  */
214
  */
214
-RemoteVideo.prototype._requestRemoteControlPermissions = function () {
215
+RemoteVideo.prototype._requestRemoteControlPermissions = function() {
215
     APP.remoteControl.controller.requestPermissions(
216
     APP.remoteControl.controller.requestPermissions(
216
         this.id, this.VideoLayout.getLargeVideoWrapper()).then(result => {
217
         this.id, this.VideoLayout.getLargeVideoWrapper()).then(result => {
217
-        if(result === null) {
218
+        if (result === null) {
218
             return;
219
             return;
219
         }
220
         }
220
         this.updateRemoteVideoMenu();
221
         this.updateRemoteVideoMenu();
221
         APP.UI.messageHandler.notify(
222
         APP.UI.messageHandler.notify(
222
-            "dialog.remoteControlTitle",
223
-            (result === false) ? "dialog.remoteControlDeniedMessage"
224
-                : "dialog.remoteControlAllowedMessage",
225
-            {user: this.user.getDisplayName()
226
-                || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME}
223
+            'dialog.remoteControlTitle',
224
+            result === false ? 'dialog.remoteControlDeniedMessage'
225
+                : 'dialog.remoteControlAllowedMessage',
226
+            { user: this.user.getDisplayName()
227
+                || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME }
227
         );
228
         );
228
-        if(result === true) {//the remote control permissions has been granted
229
+        if (result === true) {
230
+            // the remote control permissions has been granted
229
             // pin the controlled participant
231
             // pin the controlled participant
230
-            let pinnedId = this.VideoLayout.getPinnedId();
231
-            if(pinnedId !== this.id) {
232
+            const pinnedId = this.VideoLayout.getPinnedId();
233
+
234
+            if (pinnedId !== this.id) {
232
                 this.VideoLayout.handleVideoThumbClicked(this.id);
235
                 this.VideoLayout.handleVideoThumbClicked(this.id);
233
             }
236
             }
234
         }
237
         }
236
         logger.error(error);
239
         logger.error(error);
237
         this.updateRemoteVideoMenu();
240
         this.updateRemoteVideoMenu();
238
         APP.UI.messageHandler.notify(
241
         APP.UI.messageHandler.notify(
239
-            "dialog.remoteControlTitle",
240
-            "dialog.remoteControlErrorMessage",
241
-            {user: this.user.getDisplayName()
242
-                || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME}
242
+            'dialog.remoteControlTitle',
243
+            'dialog.remoteControlErrorMessage',
244
+            { user: this.user.getDisplayName()
245
+                || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME }
243
         );
246
         );
244
     });
247
     });
245
     this.updateRemoteVideoMenu();
248
     this.updateRemoteVideoMenu();
248
 /**
251
 /**
249
  * Stops remote control session.
252
  * Stops remote control session.
250
  */
253
  */
251
-RemoteVideo.prototype._stopRemoteControl = function () {
254
+RemoteVideo.prototype._stopRemoteControl = function() {
252
     // send message about stopping
255
     // send message about stopping
253
     APP.remoteControl.controller.stop();
256
     APP.remoteControl.controller.stop();
254
     this.updateRemoteVideoMenu();
257
     this.updateRemoteVideoMenu();
259
  *
262
  *
260
  * @returns {Element} audio element
263
  * @returns {Element} audio element
261
  */
264
  */
262
-RemoteVideo.prototype._getAudioElement = function () {
265
+RemoteVideo.prototype._getAudioElement = function() {
263
     return this._audioStreamElement;
266
     return this._audioStreamElement;
264
 };
267
 };
265
 
268
 
268
  *
271
  *
269
  * @returns {boolean} true if the volume can be adjusted.
272
  * @returns {boolean} true if the volume can be adjusted.
270
  */
273
  */
271
-RemoteVideo.prototype._canSetAudioVolume = function () {
274
+RemoteVideo.prototype._canSetAudioVolume = function() {
272
     const audioElement = this._getAudioElement();
275
     const audioElement = this._getAudioElement();
276
+
277
+
273
     return audioElement && audioElement.volume !== undefined;
278
     return audioElement && audioElement.volume !== undefined;
274
 };
279
 };
275
 
280
 
278
  *
283
  *
279
  * @param {int} newVal - The value to set the slider to.
284
  * @param {int} newVal - The value to set the slider to.
280
  */
285
  */
281
-RemoteVideo.prototype._setAudioVolume = function (newVal) {
286
+RemoteVideo.prototype._setAudioVolume = function(newVal) {
282
     if (this._canSetAudioVolume()) {
287
     if (this._canSetAudioVolume()) {
283
         this._getAudioElement().volume = newVal;
288
         this._getAudioElement().volume = newVal;
284
     }
289
     }
289
  *
294
  *
290
  * @param isMuted the new muted state to update to
295
  * @param isMuted the new muted state to update to
291
  */
296
  */
292
-RemoteVideo.prototype.updateRemoteVideoMenu = function (
297
+RemoteVideo.prototype.updateRemoteVideoMenu = function(
293
         isMuted = this.isAudioMuted) {
298
         isMuted = this.isAudioMuted) {
294
     this.isAudioMuted = isMuted;
299
     this.isAudioMuted = isMuted;
295
 
300
 
302
  */
307
  */
303
 RemoteVideo.prototype.setVideoMutedView = function(isMuted) {
308
 RemoteVideo.prototype.setVideoMutedView = function(isMuted) {
304
     SmallVideo.prototype.setVideoMutedView.call(this, isMuted);
309
     SmallVideo.prototype.setVideoMutedView.call(this, isMuted);
310
+
305
     // Update 'mutedWhileDisconnected' flag
311
     // Update 'mutedWhileDisconnected' flag
306
     this._figureOutMutedWhileDisconnected();
312
     this._figureOutMutedWhileDisconnected();
307
 };
313
 };
314
  */
320
  */
315
 RemoteVideo.prototype._figureOutMutedWhileDisconnected = function() {
321
 RemoteVideo.prototype._figureOutMutedWhileDisconnected = function() {
316
     const isActive = this.isConnectionActive();
322
     const isActive = this.isConnectionActive();
323
+
317
     if (!isActive && this.isVideoMuted) {
324
     if (!isActive && this.isVideoMuted) {
318
         this.mutedWhileDisconnected = true;
325
         this.mutedWhileDisconnected = true;
319
     } else if (isActive && !this.isVideoMuted) {
326
     } else if (isActive && !this.isVideoMuted) {
326
  * given <tt>parentElement</tt>.
333
  * given <tt>parentElement</tt>.
327
  *
334
  *
328
  */
335
  */
329
-RemoteVideo.prototype.addRemoteVideoMenu = function () {
336
+RemoteVideo.prototype.addRemoteVideoMenu = function() {
330
     if (interfaceConfig.filmStripOnly) {
337
     if (interfaceConfig.filmStripOnly) {
331
         return;
338
         return;
332
     }
339
     }
343
  * @param stream the MediaStream
350
  * @param stream the MediaStream
344
  * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
351
  * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
345
  */
352
  */
346
-RemoteVideo.prototype.removeRemoteStreamElement = function (stream) {
347
-    if (!this.container)
353
+RemoteVideo.prototype.removeRemoteStreamElement = function(stream) {
354
+    if (!this.container) {
348
         return false;
355
         return false;
356
+    }
349
 
357
 
350
-    var isVideo = stream.isVideoTrack();
358
+    const isVideo = stream.isVideoTrack();
359
+
360
+    const elementID = SmallVideo.getStreamElementID(stream);
361
+    const select = $(`#${elementID}`);
351
 
362
 
352
-    var elementID = SmallVideo.getStreamElementID(stream);
353
-    var select = $('#' + elementID);
354
     select.remove();
363
     select.remove();
355
 
364
 
356
     if (isVideo) {
365
     if (isVideo) {
357
         this.wasVideoPlayed = false;
366
         this.wasVideoPlayed = false;
358
     }
367
     }
359
 
368
 
360
-    logger.info((isVideo ? "Video" : "Audio") +
361
-                 " removed " + this.id, select);
369
+    logger.info(`${isVideo ? 'Video' : 'Audio'
370
+    } removed ${this.id}`, select);
362
 
371
 
363
     // when removing only the video element and we are on stage
372
     // when removing only the video element and we are on stage
364
     // update the stage
373
     // update the stage
386
  * The remote video is considered "playable" once the stream has started
395
  * The remote video is considered "playable" once the stream has started
387
  * according to the {@link #hasVideoStarted} result.
396
  * according to the {@link #hasVideoStarted} result.
388
  * It will be allowed to display video also in
397
  * It will be allowed to display video also in
389
- * {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video was ever played
390
- * and was not muted while not in ACTIVE state. This basically means that there
391
- * is stalled video image cached that could be displayed. It's used to show
392
- * "grey video image" in user's thumbnail when there are connectivity issues.
398
+ * {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video was ever
399
+ *  played and was not muted while not in ACTIVE state. This basically means
400
+ * that there is stalled video image cached that could be displayed. It's used
401
+ * to show "grey video image" in user's thumbnail when there are connectivity
402
+ * issues.
393
  *
403
  *
394
  * @inheritdoc
404
  * @inheritdoc
395
  * @override
405
  * @override
396
  */
406
  */
397
-RemoteVideo.prototype.isVideoPlayable = function () {
407
+RemoteVideo.prototype.isVideoPlayable = function() {
398
     const connectionState
408
     const connectionState
399
         = APP.conference.getParticipantConnectionStatus(this.id);
409
         = APP.conference.getParticipantConnectionStatus(this.id);
400
 
410
 
408
 /**
418
 /**
409
  * @inheritDoc
419
  * @inheritDoc
410
  */
420
  */
411
-RemoteVideo.prototype.updateView = function () {
421
+RemoteVideo.prototype.updateView = function() {
412
     this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
422
     this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
413
 
423
 
414
     this.updateConnectionStatusIndicator();
424
     this.updateConnectionStatusIndicator();
421
 /**
431
 /**
422
  * Updates the UI to reflect user's connectivity status.
432
  * Updates the UI to reflect user's connectivity status.
423
  */
433
  */
424
-RemoteVideo.prototype.updateConnectionStatusIndicator = function () {
434
+RemoteVideo.prototype.updateConnectionStatusIndicator = function() {
425
     const connectionStatus = this.user.getConnectionStatus();
435
     const connectionStatus = this.user.getConnectionStatus();
426
 
436
 
427
     logger.debug(`${this.id} thumbnail connection status: ${connectionStatus}`);
437
     logger.debug(`${this.id} thumbnail connection status: ${connectionStatus}`);
433
 
443
 
434
     const isInterrupted
444
     const isInterrupted
435
         = connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED;
445
         = connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED;
446
+
436
     // Toggle thumbnail video problem filter
447
     // Toggle thumbnail video problem filter
448
+
437
     this.selectVideoElement().toggleClass(
449
     this.selectVideoElement().toggleClass(
438
-        "videoThumbnailProblemFilter", isInterrupted);
450
+        'videoThumbnailProblemFilter', isInterrupted);
439
     this.$avatar().toggleClass(
451
     this.$avatar().toggleClass(
440
-        "videoThumbnailProblemFilter", isInterrupted);
452
+        'videoThumbnailProblemFilter', isInterrupted);
441
 };
453
 };
442
 
454
 
443
 /**
455
 /**
444
  * Removes RemoteVideo from the page.
456
  * Removes RemoteVideo from the page.
445
  */
457
  */
446
-RemoteVideo.prototype.remove = function () {
447
-    logger.log("Remove thumbnail", this.id);
458
+RemoteVideo.prototype.remove = function() {
459
+    logger.log('Remove thumbnail', this.id);
448
 
460
 
449
     this.removeAudioLevelIndicator();
461
     this.removeAudioLevelIndicator();
450
 
462
 
470
     // Make sure that the large video is updated if are removing its
482
     // Make sure that the large video is updated if are removing its
471
     // corresponding small video.
483
     // corresponding small video.
472
     this.VideoLayout.updateAfterThumbRemoved(this.id);
484
     this.VideoLayout.updateAfterThumbRemoved(this.id);
485
+
473
     // Remove whole container
486
     // Remove whole container
474
     if (this.container.parentNode) {
487
     if (this.container.parentNode) {
475
         this.container.parentNode.removeChild(this.container);
488
         this.container.parentNode.removeChild(this.container);
476
     }
489
     }
477
 };
490
 };
478
 
491
 
479
-RemoteVideo.prototype.waitForPlayback = function (streamElement, stream) {
492
+RemoteVideo.prototype.waitForPlayback = function(streamElement, stream) {
493
+
494
+    const webRtcStream = stream.getOriginalStream();
495
+    const isVideo = stream.isVideoTrack();
480
 
496
 
481
-    var webRtcStream = stream.getOriginalStream();
482
-    var isVideo = stream.isVideoTrack();
483
     if (!isVideo || webRtcStream.id === 'mixedmslabel') {
497
     if (!isVideo || webRtcStream.id === 'mixedmslabel') {
484
         return;
498
         return;
485
     }
499
     }
486
 
500
 
487
-    var self = this;
501
+    const self = this;
488
 
502
 
489
     // Triggers when video playback starts
503
     // Triggers when video playback starts
490
-    var onPlayingHandler = function () {
504
+    const onPlayingHandler = function() {
491
         self.wasVideoPlayed = true;
505
         self.wasVideoPlayed = true;
492
         self.VideoLayout.remoteVideoActive(streamElement, self.id);
506
         self.VideoLayout.remoteVideoActive(streamElement, self.id);
493
         streamElement.onplaying = null;
507
         streamElement.onplaying = null;
508
+
494
         // Refresh to show the video
509
         // Refresh to show the video
495
         self.updateView();
510
         self.updateView();
496
     };
511
     };
512
+
497
     streamElement.onplaying = onPlayingHandler;
513
     streamElement.onplaying = onPlayingHandler;
498
 };
514
 };
499
 
515
 
503
  * @returns {boolean} true if this RemoteVideo has a video stream for which
519
  * @returns {boolean} true if this RemoteVideo has a video stream for which
504
  * the playback has been started.
520
  * the playback has been started.
505
  */
521
  */
506
-RemoteVideo.prototype.hasVideoStarted = function () {
522
+RemoteVideo.prototype.hasVideoStarted = function() {
507
     return this.wasVideoPlayed;
523
     return this.wasVideoPlayed;
508
 };
524
 };
509
 
525
 
510
-RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
526
+RemoteVideo.prototype.addRemoteStreamElement = function(stream) {
511
     if (!this.container) {
527
     if (!this.container) {
512
         return;
528
         return;
513
     }
529
     }
514
 
530
 
515
-    let isVideo = stream.isVideoTrack();
531
+    const isVideo = stream.isVideoTrack();
532
+
516
     isVideo ? this.videoStream = stream : this.audioStream = stream;
533
     isVideo ? this.videoStream = stream : this.audioStream = stream;
517
 
534
 
518
-    if (isVideo)
535
+    if (isVideo) {
519
         this.setVideoType(stream.videoType);
536
         this.setVideoType(stream.videoType);
537
+    }
520
 
538
 
521
     // Add click handler.
539
     // Add click handler.
522
-    let onClickHandler = (event) => {
540
+    const onClickHandler = event => {
523
         const $source = $(event.target || event.srcElement);
541
         const $source = $(event.target || event.srcElement);
524
         const { classList } = event.target;
542
         const { classList } = event.target;
525
 
543
 
546
             event.stopPropagation();
564
             event.stopPropagation();
547
             event.preventDefault();
565
             event.preventDefault();
548
         }
566
         }
567
+
549
         return false;
568
         return false;
550
     };
569
     };
570
+
551
     this.container.onclick = onClickHandler;
571
     this.container.onclick = onClickHandler;
552
 
572
 
553
-    if(!stream.getOriginalStream())
573
+    if (!stream.getOriginalStream()) {
554
         return;
574
         return;
575
+    }
555
 
576
 
556
     let streamElement = SmallVideo.createStreamElement(stream);
577
     let streamElement = SmallVideo.createStreamElement(stream);
557
 
578
 
591
  */
612
  */
592
 RemoteVideo.prototype.setDisplayName = function(displayName) {
613
 RemoteVideo.prototype.setDisplayName = function(displayName) {
593
     if (!this.container) {
614
     if (!this.container) {
594
-        logger.warn( "Unable to set displayName - " + this.videoSpanId +
595
-                " does not exist");
615
+        logger.warn(`Unable to set displayName - ${this.videoSpanId
616
+        } does not exist`);
617
+
596
         return;
618
         return;
597
     }
619
     }
598
 
620
 
610
  * @param videoElementId the id of local or remote video element.
632
  * @param videoElementId the id of local or remote video element.
611
  */
633
  */
612
 RemoteVideo.prototype.removeRemoteVideoMenu = function() {
634
 RemoteVideo.prototype.removeRemoteVideoMenu = function() {
613
-    var menuSpan = this.$container.find('.remotevideomenu');
635
+    const menuSpan = this.$container.find('.remotevideomenu');
614
 
636
 
615
     if (menuSpan.length) {
637
     if (menuSpan.length) {
616
         ReactDOM.unmountComponentAtNode(menuSpan.get(0));
638
         ReactDOM.unmountComponentAtNode(menuSpan.get(0));
625
  *
647
  *
626
  * @return {void}
648
  * @return {void}
627
  */
649
  */
628
-RemoteVideo.prototype.addPresenceLabel = function () {
650
+RemoteVideo.prototype.addPresenceLabel = function() {
629
     const presenceLabelContainer
651
     const presenceLabelContainer
630
         = this.container.querySelector('.presence-label-container');
652
         = this.container.querySelector('.presence-label-container');
631
 
653
 
632
     if (presenceLabelContainer) {
654
     if (presenceLabelContainer) {
633
-        /* jshint ignore:start */
634
         ReactDOM.render(
655
         ReactDOM.render(
635
             <Provider store = { APP.store }>
656
             <Provider store = { APP.store }>
636
                 <PresenceLabel participantID = { this.id } />
657
                 <PresenceLabel participantID = { this.id } />
637
             </Provider>,
658
             </Provider>,
638
             presenceLabelContainer);
659
             presenceLabelContainer);
639
-        /* jshint ignore:end */
640
     }
660
     }
641
 };
661
 };
642
 
662
 
645
  *
665
  *
646
  * @return {void}
666
  * @return {void}
647
  */
667
  */
648
-RemoteVideo.prototype.removePresenceLabel = function () {
668
+RemoteVideo.prototype.removePresenceLabel = function() {
649
     const presenceLabelContainer
669
     const presenceLabelContainer
650
         = this.container.querySelector('.presence-label-container');
670
         = this.container.querySelector('.presence-label-container');
651
 
671
 
654
     }
674
     }
655
 };
675
 };
656
 
676
 
657
-RemoteVideo.createContainer = function (spanId) {
677
+RemoteVideo.createContainer = function(spanId) {
658
     const container = document.createElement('span');
678
     const container = document.createElement('span');
679
+
659
     container.id = spanId;
680
     container.id = spanId;
660
     container.className = 'videocontainer';
681
     container.className = 'videocontainer';
661
 
682
 
669
         <div class ='presence-label-container'></div>
690
         <div class ='presence-label-container'></div>
670
         <span class = 'remotevideomenu'></span>`;
691
         <span class = 'remotevideomenu'></span>`;
671
 
692
 
672
-    var remotes = document.getElementById('filmstripRemoteVideosContainer');
693
+    const remotes = document.getElementById('filmstripRemoteVideosContainer');
694
+
695
+
673
     return remotes.appendChild(container);
696
     return remotes.appendChild(container);
674
 };
697
 };
675
 
698
 

+ 119
- 102
modules/UI/videolayout/SmallVideo.js View File

25
 } from '../../../react/features/filmstrip';
25
 } from '../../../react/features/filmstrip';
26
 /* eslint-enable no-unused-vars */
26
 /* eslint-enable no-unused-vars */
27
 
27
 
28
-const logger = require("jitsi-meet-logger").getLogger(__filename);
28
+const logger = require('jitsi-meet-logger').getLogger(__filename);
29
 
29
 
30
-import Avatar from "../avatar/Avatar";
31
-import UIUtil from "../util/UIUtil";
32
-import UIEvents from "../../../service/UI/UIEvents";
30
+import Avatar from '../avatar/Avatar';
31
+import UIUtil from '../util/UIUtil';
32
+import UIEvents from '../../../service/UI/UIEvents';
33
 
33
 
34
 const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
34
 const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
35
 
35
 
39
  * @constant
39
  * @constant
40
  */
40
  */
41
 const DISPLAY_VIDEO = 0;
41
 const DISPLAY_VIDEO = 0;
42
+
42
 /**
43
 /**
43
  * Display mode constant used when the user's avatar is being displayed on
44
  * Display mode constant used when the user's avatar is being displayed on
44
  * the small video.
45
  * the small video.
46
  * @constant
47
  * @constant
47
  */
48
  */
48
 const DISPLAY_AVATAR = 1;
49
 const DISPLAY_AVATAR = 1;
50
+
49
 /**
51
 /**
50
  * Display mode constant used when neither video nor avatar is being displayed
52
  * Display mode constant used when neither video nor avatar is being displayed
51
  * on the small video. And we just show the display name.
53
  * on the small video. And we just show the display name.
70
  */
72
  */
71
 const DISPLAY_AVATAR_WITH_NAME = 4;
73
 const DISPLAY_AVATAR_WITH_NAME = 4;
72
 
74
 
75
+/**
76
+ * Constructor.
77
+ */
73
 function SmallVideo(VideoLayout) {
78
 function SmallVideo(VideoLayout) {
74
     this._isModerator = false;
79
     this._isModerator = false;
75
     this.isAudioMuted = false;
80
     this.isAudioMuted = false;
80
     this.VideoLayout = VideoLayout;
85
     this.VideoLayout = VideoLayout;
81
     this.videoIsHovered = false;
86
     this.videoIsHovered = false;
82
     this.hideDisplayName = false;
87
     this.hideDisplayName = false;
88
+
83
     // we can stop updating the thumbnail
89
     // we can stop updating the thumbnail
84
     this.disableUpdateView = false;
90
     this.disableUpdateView = false;
85
 
91
 
136
  *
142
  *
137
  * @returns the identifier of this small video
143
  * @returns the identifier of this small video
138
  */
144
  */
139
-SmallVideo.prototype.getId = function () {
145
+SmallVideo.prototype.getId = function() {
140
     return this.id;
146
     return this.id;
141
 };
147
 };
142
 
148
 
145
  * @return <tt>true</tt> if this small video isn't currently visible and
151
  * @return <tt>true</tt> if this small video isn't currently visible and
146
  * <tt>false</tt> - otherwise.
152
  * <tt>false</tt> - otherwise.
147
  */
153
  */
148
-SmallVideo.prototype.isVisible = function () {
154
+SmallVideo.prototype.isVisible = function() {
149
     return this.$container.is(':visible');
155
     return this.$container.is(':visible');
150
 };
156
 };
151
 
157
 
153
  * Enables / disables the device availability icons for this small video.
159
  * Enables / disables the device availability icons for this small video.
154
  * @param {enable} set to {true} to enable and {false} to disable
160
  * @param {enable} set to {true} to enable and {false} to disable
155
  */
161
  */
156
-SmallVideo.prototype.enableDeviceAvailabilityIcons = function (enable) {
157
-    if (typeof enable === "undefined")
162
+SmallVideo.prototype.enableDeviceAvailabilityIcons = function(enable) {
163
+    if (typeof enable === 'undefined') {
158
         return;
164
         return;
165
+    }
159
 
166
 
160
     this.deviceAvailabilityIconsEnabled = enable;
167
     this.deviceAvailabilityIconsEnabled = enable;
161
 };
168
 };
164
  * Sets the device "non" availability icons.
171
  * Sets the device "non" availability icons.
165
  * @param devices the devices, which will be checked for availability
172
  * @param devices the devices, which will be checked for availability
166
  */
173
  */
167
-SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
168
-    if (!this.deviceAvailabilityIconsEnabled)
174
+SmallVideo.prototype.setDeviceAvailabilityIcons = function(devices) {
175
+    if (!this.deviceAvailabilityIconsEnabled) {
169
         return;
176
         return;
177
+    }
170
 
178
 
171
-    if(!this.container)
179
+    if (!this.container) {
172
         return;
180
         return;
181
+    }
173
 
182
 
174
-    var noMic = this.$container.find('.noMic');
175
-    var noVideo =  this.$container.find('.noVideo');
183
+    const noMic = this.$container.find('.noMic');
184
+    const noVideo = this.$container.find('.noVideo');
176
 
185
 
177
     noMic.remove();
186
     noMic.remove();
178
     noVideo.remove();
187
     noVideo.remove();
179
     if (!devices.audio) {
188
     if (!devices.audio) {
180
         this.container.appendChild(
189
         this.container.appendChild(
181
-            document.createElement("div")).setAttribute("class", "noMic");
190
+            document.createElement('div')).setAttribute('class', 'noMic');
182
     }
191
     }
183
 
192
 
184
     if (!devices.video) {
193
     if (!devices.video) {
185
         this.container.appendChild(
194
         this.container.appendChild(
186
-            document.createElement("div")).setAttribute("class", "noVideo");
195
+            document.createElement('div')).setAttribute('class', 'noVideo');
187
     }
196
     }
188
 
197
 
189
     if (!devices.audio && !devices.video) {
198
     if (!devices.audio && !devices.video) {
190
-        noMic.css("background-position", "75%");
191
-        noVideo.css("background-position", "25%");
192
-        noVideo.css("background-color", "transparent");
199
+        noMic.css('background-position', '75%');
200
+        noVideo.css('background-position', '25%');
201
+        noVideo.css('background-color', 'transparent');
193
     }
202
     }
194
 };
203
 };
195
 
204
 
200
  * lib-jitsi-meet.
209
  * lib-jitsi-meet.
201
  * @param videoType 'camera' or 'desktop', or 'sharedvideo'.
210
  * @param videoType 'camera' or 'desktop', or 'sharedvideo'.
202
  */
211
  */
203
-SmallVideo.prototype.setVideoType = function (videoType) {
212
+SmallVideo.prototype.setVideoType = function(videoType) {
204
     this.videoType = videoType;
213
     this.videoType = videoType;
205
 };
214
 };
206
 
215
 
211
  * lib-jitsi-meet.
220
  * lib-jitsi-meet.
212
  * @returns {String} 'camera', 'screen', 'sharedvideo', or undefined.
221
  * @returns {String} 'camera', 'screen', 'sharedvideo', or undefined.
213
  */
222
  */
214
-SmallVideo.prototype.getVideoType = function () {
223
+SmallVideo.prototype.getVideoType = function() {
215
     return this.videoType;
224
     return this.videoType;
216
 };
225
 };
217
 
226
 
218
 /**
227
 /**
219
  * Creates an audio or video element for a particular MediaStream.
228
  * Creates an audio or video element for a particular MediaStream.
220
  */
229
  */
221
-SmallVideo.createStreamElement = function (stream) {
222
-    let isVideo = stream.isVideoTrack();
230
+SmallVideo.createStreamElement = function(stream) {
231
+    const isVideo = stream.isVideoTrack();
223
 
232
 
224
-    let element = isVideo
233
+    const element = isVideo
225
         ? document.createElement('video')
234
         ? document.createElement('video')
226
         : document.createElement('audio');
235
         : document.createElement('audio');
236
+
227
     if (isVideo) {
237
     if (isVideo) {
228
-        element.setAttribute("muted", "true");
238
+        element.setAttribute('muted', 'true');
229
     }
239
     }
230
 
240
 
231
     RTCUIHelper.setAutoPlay(element, true);
241
     RTCUIHelper.setAutoPlay(element, true);
238
 /**
248
 /**
239
  * Returns the element id for a particular MediaStream.
249
  * Returns the element id for a particular MediaStream.
240
  */
250
  */
241
-SmallVideo.getStreamElementID = function (stream) {
242
-    let isVideo = stream.isVideoTrack();
251
+SmallVideo.getStreamElementID = function(stream) {
252
+    const isVideo = stream.isVideoTrack();
243
 
253
 
244
     return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
254
     return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
245
 };
255
 };
247
 /**
257
 /**
248
  * Configures hoverIn/hoverOut handlers. Depends on connection indicator.
258
  * Configures hoverIn/hoverOut handlers. Depends on connection indicator.
249
  */
259
  */
250
-SmallVideo.prototype.bindHoverHandler = function () {
260
+SmallVideo.prototype.bindHoverHandler = function() {
251
     // Add hover handler
261
     // Add hover handler
252
     this.$container.hover(
262
     this.$container.hover(
253
         () => {
263
         () => {
268
 
278
 
269
  * @returns {void}
279
  * @returns {void}
270
  */
280
  */
271
-SmallVideo.prototype.removeConnectionIndicator = function () {
281
+SmallVideo.prototype.removeConnectionIndicator = function() {
272
     this._showConnectionIndicator = false;
282
     this._showConnectionIndicator = false;
273
 
283
 
274
     this.updateIndicators();
284
     this.updateIndicators();
279
 
289
 
280
  * @returns {void}
290
  * @returns {void}
281
  */
291
  */
282
-SmallVideo.prototype.updateConnectionStatus = function (connectionStatus) {
292
+SmallVideo.prototype.updateConnectionStatus = function(connectionStatus) {
283
     this._connectionStatus = connectionStatus;
293
     this._connectionStatus = connectionStatus;
284
     this.updateIndicators();
294
     this.updateIndicators();
285
 };
295
 };
290
  * @param {boolean} isMuted indicates if the muted element should be shown
300
  * @param {boolean} isMuted indicates if the muted element should be shown
291
  * or hidden
301
  * or hidden
292
  */
302
  */
293
-SmallVideo.prototype.showAudioIndicator = function (isMuted) {
303
+SmallVideo.prototype.showAudioIndicator = function(isMuted) {
294
     this.isAudioMuted = isMuted;
304
     this.isAudioMuted = isMuted;
295
     this.updateStatusBar();
305
     this.updateStatusBar();
296
 };
306
 };
315
  *
325
  *
316
  * @returns {void}
326
  * @returns {void}
317
  */
327
  */
318
-SmallVideo.prototype.updateStatusBar = function () {
328
+SmallVideo.prototype.updateStatusBar = function() {
319
     const statusBarContainer
329
     const statusBarContainer
320
         = this.container.querySelector('.videocontainer__toolbar');
330
         = this.container.querySelector('.videocontainer__toolbar');
321
     const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
331
     const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
322
 
332
 
323
-    /* jshint ignore:start */
324
     ReactDOM.render(
333
     ReactDOM.render(
325
         <I18nextProvider i18n = { i18next }>
334
         <I18nextProvider i18n = { i18next }>
326
             <div>
335
             <div>
339
             </div>
348
             </div>
340
         </I18nextProvider>,
349
         </I18nextProvider>,
341
         statusBarContainer);
350
         statusBarContainer);
342
-    /* jshint ignore:end */
343
 };
351
 };
344
 
352
 
345
 /**
353
 /**
346
  * Adds the element indicating the moderator(owner) of the conference.
354
  * Adds the element indicating the moderator(owner) of the conference.
347
  */
355
  */
348
-SmallVideo.prototype.addModeratorIndicator = function () {
356
+SmallVideo.prototype.addModeratorIndicator = function() {
349
     this._isModerator = true;
357
     this._isModerator = true;
350
     this.updateStatusBar();
358
     this.updateStatusBar();
351
 };
359
 };
355
  *
363
  *
356
  * @returns {void}
364
  * @returns {void}
357
  */
365
  */
358
-SmallVideo.prototype.addAudioLevelIndicator = function () {
366
+SmallVideo.prototype.addAudioLevelIndicator = function() {
359
     let audioLevelContainer = this._getAudioLevelContainer();
367
     let audioLevelContainer = this._getAudioLevelContainer();
360
 
368
 
361
     if (audioLevelContainer) {
369
     if (audioLevelContainer) {
374
  *
382
  *
375
  * @returns {void}
383
  * @returns {void}
376
  */
384
  */
377
-SmallVideo.prototype.removeAudioLevelIndicator = function () {
385
+SmallVideo.prototype.removeAudioLevelIndicator = function() {
378
     const audioLevelContainer = this._getAudioLevelContainer();
386
     const audioLevelContainer = this._getAudioLevelContainer();
379
 
387
 
380
     if (audioLevelContainer) {
388
     if (audioLevelContainer) {
388
  * @param lvl the new audio level to set
396
  * @param lvl the new audio level to set
389
  * @returns {void}
397
  * @returns {void}
390
  */
398
  */
391
-SmallVideo.prototype.updateAudioLevelIndicator = function (lvl = 0) {
399
+SmallVideo.prototype.updateAudioLevelIndicator = function(lvl = 0) {
392
     const audioLevelContainer = this._getAudioLevelContainer();
400
     const audioLevelContainer = this._getAudioLevelContainer();
393
 
401
 
394
     if (audioLevelContainer) {
402
     if (audioLevelContainer) {
395
-        /* jshint ignore:start */
396
         ReactDOM.render(
403
         ReactDOM.render(
397
             <AudioLevelIndicator
404
             <AudioLevelIndicator
398
                 audioLevel = { lvl }/>,
405
                 audioLevel = { lvl }/>,
399
             audioLevelContainer);
406
             audioLevelContainer);
400
-        /* jshint ignore:end */
401
     }
407
     }
402
 };
408
 };
403
 
409
 
407
  *
413
  *
408
  * @returns {HTMLElement} The DOM element that holds the AudioLevelIndicator.
414
  * @returns {HTMLElement} The DOM element that holds the AudioLevelIndicator.
409
  */
415
  */
410
-SmallVideo.prototype._getAudioLevelContainer = function () {
416
+SmallVideo.prototype._getAudioLevelContainer = function() {
411
     return this.container.querySelector('.audioindicator-container');
417
     return this.container.querySelector('.audioindicator-container');
412
 };
418
 };
413
 
419
 
414
 /**
420
 /**
415
  * Removes the element indicating the moderator(owner) of the conference.
421
  * Removes the element indicating the moderator(owner) of the conference.
416
  */
422
  */
417
-SmallVideo.prototype.removeModeratorIndicator = function () {
423
+SmallVideo.prototype.removeModeratorIndicator = function() {
418
     this._isModerator = false;
424
     this._isModerator = false;
419
     this.updateStatusBar();
425
     this.updateStatusBar();
420
 };
426
 };
429
  * this function to access the video element via the 0th element of the returned
435
  * this function to access the video element via the 0th element of the returned
430
  * array (after checking its length of course!).
436
  * array (after checking its length of course!).
431
  */
437
  */
432
-SmallVideo.prototype.selectVideoElement = function () {
438
+SmallVideo.prototype.selectVideoElement = function() {
433
     return $(RTCUIHelper.findVideoElement(this.container));
439
     return $(RTCUIHelper.findVideoElement(this.container));
434
 };
440
 };
435
 
441
 
439
  * @return {jQuery|HTMLElement} a jQuery selector pointing to the HTML image
445
  * @return {jQuery|HTMLElement} a jQuery selector pointing to the HTML image
440
  * element which displays the user's avatar.
446
  * element which displays the user's avatar.
441
  */
447
  */
442
-SmallVideo.prototype.$avatar = function () {
448
+SmallVideo.prototype.$avatar = function() {
443
     return this.$container.find('.avatar-container');
449
     return this.$container.find('.avatar-container');
444
 };
450
 };
445
 
451
 
449
  * @return {jQuery} a jQuery selector pointing to the display name element of
455
  * @return {jQuery} a jQuery selector pointing to the display name element of
450
  * the video thumbnail
456
  * the video thumbnail
451
  */
457
  */
452
-SmallVideo.prototype.$displayName = function () {
458
+SmallVideo.prototype.$displayName = function() {
453
     return this.$container.find('.displayNameContainer');
459
     return this.$container.find('.displayNameContainer');
454
 };
460
 };
455
 
461
 
459
  *
465
  *
460
  * @returns {void}
466
  * @returns {void}
461
  */
467
  */
462
-SmallVideo.prototype.updateDisplayName = function (props) {
468
+SmallVideo.prototype.updateDisplayName = function(props) {
463
     const displayNameContainer
469
     const displayNameContainer
464
         = this.container.querySelector('.displayNameContainer');
470
         = this.container.querySelector('.displayNameContainer');
465
 
471
 
466
     if (displayNameContainer) {
472
     if (displayNameContainer) {
467
-        /* jshint ignore:start */
468
         ReactDOM.render(
473
         ReactDOM.render(
469
             <Provider store = { APP.store }>
474
             <Provider store = { APP.store }>
470
                 <I18nextProvider i18n = { i18next }>
475
                 <I18nextProvider i18n = { i18next }>
472
                 </I18nextProvider>
477
                 </I18nextProvider>
473
             </Provider>,
478
             </Provider>,
474
             displayNameContainer);
479
             displayNameContainer);
475
-        /* jshint ignore:end */
476
     }
480
     }
477
 };
481
 };
478
 
482
 
482
  *
486
  *
483
  * @returns {void}
487
  * @returns {void}
484
  */
488
  */
485
-SmallVideo.prototype.removeDisplayName = function () {
489
+SmallVideo.prototype.removeDisplayName = function() {
486
     const displayNameContainer
490
     const displayNameContainer
487
         = this.container.querySelector('.displayNameContainer');
491
         = this.container.querySelector('.displayNameContainer');
488
 
492
 
498
  * @param isFocused indicates if the thumbnail should be focused/pinned or not
502
  * @param isFocused indicates if the thumbnail should be focused/pinned or not
499
  */
503
  */
500
 SmallVideo.prototype.focus = function(isFocused) {
504
 SmallVideo.prototype.focus = function(isFocused) {
501
-    var focusedCssClass = "videoContainerFocused";
502
-    var isFocusClassEnabled = this.$container.hasClass(focusedCssClass);
505
+    const focusedCssClass = 'videoContainerFocused';
506
+    const isFocusClassEnabled = this.$container.hasClass(focusedCssClass);
503
 
507
 
504
     if (!isFocused && isFocusClassEnabled) {
508
     if (!isFocused && isFocusClassEnabled) {
505
         this.$container.removeClass(focusedCssClass);
509
         this.$container.removeClass(focusedCssClass);
506
-    }
507
-    else if (isFocused && !isFocusClassEnabled) {
510
+    } else if (isFocused && !isFocusClassEnabled) {
508
         this.$container.addClass(focusedCssClass);
511
         this.$container.addClass(focusedCssClass);
509
     }
512
     }
510
 };
513
 };
511
 
514
 
512
-SmallVideo.prototype.hasVideo = function () {
515
+SmallVideo.prototype.hasVideo = function() {
513
     return this.selectVideoElement().length !== 0;
516
     return this.selectVideoElement().length !== 0;
514
 };
517
 };
515
 
518
 
520
  * @return {boolean} <tt>true</tt> if the user is displayed on the large video
523
  * @return {boolean} <tt>true</tt> if the user is displayed on the large video
521
  * or <tt>false</tt> otherwise.
524
  * or <tt>false</tt> otherwise.
522
  */
525
  */
523
-SmallVideo.prototype.isCurrentlyOnLargeVideo = function () {
526
+SmallVideo.prototype.isCurrentlyOnLargeVideo = function() {
524
     return this.VideoLayout.isCurrentlyOnLarge(this.id);
527
     return this.VideoLayout.isCurrentlyOnLarge(this.id);
525
 };
528
 };
526
 
529
 
550
         && this.selectVideoElement().length
553
         && this.selectVideoElement().length
551
         && !APP.conference.isAudioOnly()) {
554
         && !APP.conference.isAudioOnly()) {
552
         // check hovering and change state to video with name
555
         // check hovering and change state to video with name
553
-        return this._isHovered() ?
554
-            DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
555
-    } else {
556
-        // check hovering and change state to avatar with name
557
-        return this._isHovered() ?
558
-            DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
556
+        return this._isHovered()
557
+            ? DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
559
     }
558
     }
559
+
560
+    // check hovering and change state to avatar with name
561
+    return this._isHovered()
562
+        ? DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
563
+
560
 };
564
 };
561
 
565
 
562
 /**
566
 /**
565
  * indicator is shown(hovered).
569
  * indicator is shown(hovered).
566
  * @private
570
  * @private
567
  */
571
  */
568
-SmallVideo.prototype._isHovered = function () {
572
+SmallVideo.prototype._isHovered = function() {
569
     return this.videoIsHovered || this._popoverIsHovered;
573
     return this.videoIsHovered || this._popoverIsHovered;
570
 };
574
 };
571
 
575
 
577
  * @param show whether we should show the avatar or not
581
  * @param show whether we should show the avatar or not
578
  * video because there is no dominant speaker and no focused speaker
582
  * video because there is no dominant speaker and no focused speaker
579
  */
583
  */
580
-SmallVideo.prototype.updateView = function () {
581
-    if (this.disableUpdateView)
584
+SmallVideo.prototype.updateView = function() {
585
+    if (this.disableUpdateView) {
582
         return;
586
         return;
587
+    }
583
 
588
 
584
     if (!this.hasAvatar) {
589
     if (!this.hasAvatar) {
585
         if (this.id) {
590
         if (this.id) {
586
             // Init avatar
591
             // Init avatar
587
             this.avatarChanged(Avatar.getAvatarUrl(this.id));
592
             this.avatarChanged(Avatar.getAvatarUrl(this.id));
588
         } else {
593
         } else {
589
-            logger.error("Unable to init avatar - no id", this);
594
+            logger.error('Unable to init avatar - no id', this);
595
+
590
             return;
596
             return;
591
         }
597
         }
592
     }
598
     }
593
 
599
 
594
     // Determine whether video, avatar or blackness should be displayed
600
     // Determine whether video, avatar or blackness should be displayed
595
-    let displayMode = this.selectDisplayMode();
601
+    const displayMode = this.selectDisplayMode();
602
+
596
     // Show/hide video.
603
     // Show/hide video.
604
+
597
     UIUtil.setVisibleBySelector(this.selectVideoElement(),
605
     UIUtil.setVisibleBySelector(this.selectVideoElement(),
598
-                                (displayMode === DISPLAY_VIDEO
599
-                                || displayMode === DISPLAY_VIDEO_WITH_NAME));
606
+                                displayMode === DISPLAY_VIDEO
607
+                                || displayMode === DISPLAY_VIDEO_WITH_NAME);
608
+
600
     // Show/hide the avatar.
609
     // Show/hide the avatar.
601
     UIUtil.setVisibleBySelector(this.$avatar(),
610
     UIUtil.setVisibleBySelector(this.$avatar(),
602
-                                (displayMode === DISPLAY_AVATAR
603
-                                || displayMode === DISPLAY_AVATAR_WITH_NAME));
611
+                                displayMode === DISPLAY_AVATAR
612
+                                || displayMode === DISPLAY_AVATAR_WITH_NAME);
613
+
604
     // Show/hide the display name.
614
     // Show/hide the display name.
605
     UIUtil.setVisibleBySelector(this.$displayName(),
615
     UIUtil.setVisibleBySelector(this.$displayName(),
606
                                 !this.hideDisplayName
616
                                 !this.hideDisplayName
607
                                 && (displayMode === DISPLAY_BLACKNESS_WITH_NAME
617
                                 && (displayMode === DISPLAY_BLACKNESS_WITH_NAME
608
                                 || displayMode === DISPLAY_VIDEO_WITH_NAME
618
                                 || displayMode === DISPLAY_VIDEO_WITH_NAME
609
                                 || displayMode === DISPLAY_AVATAR_WITH_NAME));
619
                                 || displayMode === DISPLAY_AVATAR_WITH_NAME));
620
+
610
     // show hide overlay when there is a video or avatar under
621
     // show hide overlay when there is a video or avatar under
611
     // the display name
622
     // the display name
612
     UIUtil.setVisibleBySelector(this.$container.find(
623
     UIUtil.setVisibleBySelector(this.$container.find(
613
                                 '.videocontainer__hoverOverlay'),
624
                                 '.videocontainer__hoverOverlay'),
614
-                                (displayMode === DISPLAY_AVATAR_WITH_NAME
615
-                                || displayMode === DISPLAY_VIDEO_WITH_NAME));
625
+                                displayMode === DISPLAY_AVATAR_WITH_NAME
626
+                                || displayMode === DISPLAY_VIDEO_WITH_NAME);
616
 };
627
 };
617
 
628
 
618
 /**
629
 /**
622
  * @param {string} avatarUrl - The uri to the avatar image.
633
  * @param {string} avatarUrl - The uri to the avatar image.
623
  * @returns {void}
634
  * @returns {void}
624
  */
635
  */
625
-SmallVideo.prototype.avatarChanged = function (avatarUrl) {
636
+SmallVideo.prototype.avatarChanged = function(avatarUrl) {
626
     const thumbnail = this.$avatar().get(0);
637
     const thumbnail = this.$avatar().get(0);
638
+
627
     this.hasAvatar = true;
639
     this.hasAvatar = true;
628
 
640
 
629
     if (thumbnail) {
641
     if (thumbnail) {
630
-        /* jshint ignore:start */
631
         ReactDOM.render(
642
         ReactDOM.render(
632
             <AvatarDisplay
643
             <AvatarDisplay
633
                 className = 'userAvatar'
644
                 className = 'userAvatar'
634
                 uri = { avatarUrl } />,
645
                 uri = { avatarUrl } />,
635
             thumbnail
646
             thumbnail
636
         );
647
         );
637
-        /* jshint ignore:end */
638
     }
648
     }
639
 };
649
 };
640
 
650
 
644
  *
654
  *
645
  * @returns {void}
655
  * @returns {void}
646
  */
656
  */
647
-SmallVideo.prototype.removeAvatar = function () {
657
+SmallVideo.prototype.removeAvatar = function() {
648
     const thumbnail = this.$avatar().get(0);
658
     const thumbnail = this.$avatar().get(0);
649
 
659
 
650
     if (thumbnail) {
660
     if (thumbnail) {
656
  * Shows or hides the dominant speaker indicator.
666
  * Shows or hides the dominant speaker indicator.
657
  * @param show whether to show or hide.
667
  * @param show whether to show or hide.
658
  */
668
  */
659
-SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
669
+SmallVideo.prototype.showDominantSpeakerIndicator = function(show) {
660
     // Don't create and show dominant speaker indicator if
670
     // Don't create and show dominant speaker indicator if
661
     // DISABLE_DOMINANT_SPEAKER_INDICATOR is true
671
     // DISABLE_DOMINANT_SPEAKER_INDICATOR is true
662
-    if (interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR)
672
+    if (interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR) {
663
         return;
673
         return;
674
+    }
664
 
675
 
665
     if (!this.container) {
676
     if (!this.container) {
666
-        logger.warn( "Unable to set dominant speaker indicator - "
667
-            + this.videoSpanId + " does not exist");
677
+        logger.warn(`Unable to set dominant speaker indicator - ${
678
+            this.videoSpanId} does not exist`);
679
+
668
         return;
680
         return;
669
     }
681
     }
670
 
682
 
677
  * Shows or hides the raised hand indicator.
689
  * Shows or hides the raised hand indicator.
678
  * @param show whether to show or hide.
690
  * @param show whether to show or hide.
679
  */
691
  */
680
-SmallVideo.prototype.showRaisedHandIndicator = function (show) {
692
+SmallVideo.prototype.showRaisedHandIndicator = function(show) {
681
     if (!this.container) {
693
     if (!this.container) {
682
-        logger.warn( "Unable to raised hand indication - "
683
-            + this.videoSpanId + " does not exist");
694
+        logger.warn(`Unable to raised hand indication - ${
695
+            this.videoSpanId} does not exist`);
696
+
684
         return;
697
         return;
685
     }
698
     }
686
 
699
 
695
  * is added, and will fire a RESOLUTION_CHANGED event.
708
  * is added, and will fire a RESOLUTION_CHANGED event.
696
  */
709
  */
697
 SmallVideo.prototype.waitForResolutionChange = function() {
710
 SmallVideo.prototype.waitForResolutionChange = function() {
698
-    let beforeChange = window.performance.now();
699
-    let videos = this.selectVideoElement();
700
-    if (!videos || !videos.length || videos.length <= 0)
711
+    const beforeChange = window.performance.now();
712
+    const videos = this.selectVideoElement();
713
+
714
+    if (!videos || !videos.length || videos.length <= 0) {
701
         return;
715
         return;
702
-    let video = videos[0];
703
-    let oldWidth = video.videoWidth;
704
-    let oldHeight = video.videoHeight;
716
+    }
717
+    const video = videos[0];
718
+    const oldWidth = video.videoWidth;
719
+    const oldHeight = video.videoHeight;
720
+
705
     video.onresize = () => {
721
     video.onresize = () => {
722
+        // eslint-disable-next-line eqeqeq
706
         if (video.videoWidth != oldWidth || video.videoHeight != oldHeight) {
723
         if (video.videoWidth != oldWidth || video.videoHeight != oldHeight) {
707
             // Only run once.
724
             // Only run once.
708
             video.onresize = null;
725
             video.onresize = null;
709
 
726
 
710
-            let delay = window.performance.now() - beforeChange;
711
-            let emitter = this.VideoLayout.getEventEmitter();
727
+            const delay = window.performance.now() - beforeChange;
728
+            const emitter = this.VideoLayout.getEventEmitter();
729
+
712
             if (emitter) {
730
             if (emitter) {
713
                 emitter.emit(
731
                 emitter.emit(
714
                         UIEvents.RESOLUTION_CHANGED,
732
                         UIEvents.RESOLUTION_CHANGED,
715
                         this.getId(),
733
                         this.getId(),
716
-                        oldWidth + "x" + oldHeight,
717
-                        video.videoWidth + "x" + video.videoHeight,
734
+                        `${oldWidth}x${oldHeight}`,
735
+                        `${video.videoWidth}x${video.videoHeight}`,
718
                         delay);
736
                         delay);
719
             }
737
             }
720
         }
738
         }
735
  */
753
  */
736
 SmallVideo.prototype.initBrowserSpecificProperties = function() {
754
 SmallVideo.prototype.initBrowserSpecificProperties = function() {
737
 
755
 
738
-    var userAgent = window.navigator.userAgent;
739
-    if (userAgent.indexOf("QtWebEngine") > -1
740
-        && (userAgent.indexOf("Windows") > -1
741
-            || userAgent.indexOf("Linux") > -1)) {
742
-        this.$container.css("overflow", "hidden");
756
+    const userAgent = window.navigator.userAgent;
757
+
758
+    if (userAgent.indexOf('QtWebEngine') > -1
759
+        && (userAgent.indexOf('Windows') > -1
760
+            || userAgent.indexOf('Linux') > -1)) {
761
+        this.$container.css('overflow', 'hidden');
743
     }
762
     }
744
 };
763
 };
745
 
764
 
751
  * @private
770
  * @private
752
  * @returns {void}
771
  * @returns {void}
753
  */
772
  */
754
-SmallVideo.prototype.updateIndicators = function () {
773
+SmallVideo.prototype.updateIndicators = function() {
755
     const indicatorToolbar
774
     const indicatorToolbar
756
         = this.container.querySelector('.videocontainer__toptoolbar');
775
         = this.container.querySelector('.videocontainer__toptoolbar');
757
 
776
 
760
         || !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
779
         || !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
761
     const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
780
     const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
762
 
781
 
763
-    /* jshint ignore:start */
764
     ReactDOM.render(
782
     ReactDOM.render(
765
         <I18nextProvider i18n = { i18next }>
783
         <I18nextProvider i18n = { i18next }>
766
             <div>
784
             <div>
788
         </I18nextProvider>,
806
         </I18nextProvider>,
789
         indicatorToolbar
807
         indicatorToolbar
790
     );
808
     );
791
-    /* jshint ignore:end */
792
 };
809
 };
793
 
810
 
794
 /**
811
 /**
798
  * @private
815
  * @private
799
  * @returns {void}
816
  * @returns {void}
800
  */
817
  */
801
-SmallVideo.prototype._unmountIndicators = function () {
818
+SmallVideo.prototype._unmountIndicators = function() {
802
     const indicatorToolbar
819
     const indicatorToolbar
803
         = this.container.querySelector('.videocontainer__toptoolbar');
820
         = this.container.querySelector('.videocontainer__toptoolbar');
804
 
821
 
815
  * currently over the connection indicator popover.
832
  * currently over the connection indicator popover.
816
  * @returns {void}
833
  * @returns {void}
817
  */
834
  */
818
-SmallVideo.prototype._onPopoverHover = function (popoverIsHovered) {
835
+SmallVideo.prototype._onPopoverHover = function(popoverIsHovered) {
819
     this._popoverIsHovered = popoverIsHovered;
836
     this._popoverIsHovered = popoverIsHovered;
820
     this.updateView();
837
     this.updateView();
821
 };
838
 };

+ 100
- 60
modules/UI/videolayout/VideoContainer.js View File

23
  * @param videoSpaceHeight the height of the available space
23
  * @param videoSpaceHeight the height of the available space
24
  * @return an array with 2 elements, the video width and the video height
24
  * @return an array with 2 elements, the video width and the video height
25
  */
25
  */
26
-function computeDesktopVideoSize(
26
+function computeDesktopVideoSize( // eslint-disable-line max-params
27
         videoWidth,
27
         videoWidth,
28
         videoHeight,
28
         videoHeight,
29
         videoSpaceWidth,
29
         videoSpaceWidth,
30
         videoSpaceHeight) {
30
         videoSpaceHeight) {
31
-    let aspectRatio = videoWidth / videoHeight;
31
+    const aspectRatio = videoWidth / videoHeight;
32
 
32
 
33
     let availableWidth = Math.max(videoWidth, videoSpaceWidth);
33
     let availableWidth = Math.max(videoWidth, videoSpaceWidth);
34
     let availableHeight = Math.max(videoHeight, videoSpaceHeight);
34
     let availableHeight = Math.max(videoHeight, videoSpaceHeight);
35
 
35
 
36
+    // eslint-disable-next-line no-param-reassign
36
     videoSpaceHeight -= Filmstrip.getFilmstripHeight();
37
     videoSpaceHeight -= Filmstrip.getFilmstripHeight();
37
 
38
 
38
     if (availableWidth / aspectRatio >= videoSpaceHeight) {
39
     if (availableWidth / aspectRatio >= videoSpaceHeight) {
60
  * @param videoSpaceHeight the height of the video space
61
  * @param videoSpaceHeight the height of the video space
61
  * @return an array with 2 elements, the video width and the video height
62
  * @return an array with 2 elements, the video width and the video height
62
  */
63
  */
63
-function computeCameraVideoSize(
64
+function computeCameraVideoSize( // eslint-disable-line max-params
64
         videoWidth,
65
         videoWidth,
65
         videoHeight,
66
         videoHeight,
66
         videoSpaceWidth,
67
         videoSpaceWidth,
67
         videoSpaceHeight,
68
         videoSpaceHeight,
68
         videoLayoutFit) {
69
         videoLayoutFit) {
69
     const aspectRatio = videoWidth / videoHeight;
70
     const aspectRatio = videoWidth / videoHeight;
71
+
70
     switch (videoLayoutFit) {
72
     switch (videoLayoutFit) {
71
     case 'height':
73
     case 'height':
72
         return [ videoSpaceHeight * aspectRatio, videoSpaceHeight ];
74
         return [ videoSpaceHeight * aspectRatio, videoSpaceHeight ];
78
             || Infinity;
80
             || Infinity;
79
 
81
 
80
         if (videoSpaceRatio === aspectRatio) {
82
         if (videoSpaceRatio === aspectRatio) {
81
-            return [videoSpaceWidth, videoSpaceHeight];
83
+            return [ videoSpaceWidth, videoSpaceHeight ];
82
         }
84
         }
83
 
85
 
84
-        let [ width, height] = computeCameraVideoSize(
86
+        let [ width, height ] = computeCameraVideoSize(
85
             videoWidth,
87
             videoWidth,
86
             videoHeight,
88
             videoHeight,
87
             videoSpaceWidth,
89
             videoSpaceWidth,
97
             height = maxHeight;
99
             height = maxHeight;
98
             width = height * aspectRatio;
100
             width = height * aspectRatio;
99
         }
101
         }
100
-        return [width, height];
102
+
103
+        return [ width, height ];
101
     }
104
     }
102
     default:
105
     default:
103
         return [ videoWidth, videoHeight ];
106
         return [ videoWidth, videoHeight ];
111
  * @return an array with 2 elements, the horizontal indent and the vertical
114
  * @return an array with 2 elements, the horizontal indent and the vertical
112
  * indent
115
  * indent
113
  */
116
  */
114
-function getCameraVideoPosition(
117
+function getCameraVideoPosition( // eslint-disable-line max-params
115
         videoWidth,
118
         videoWidth,
116
         videoHeight,
119
         videoHeight,
117
         videoSpaceWidth,
120
         videoSpaceWidth,
120
     // full screen mode and this is why we use the screen height in this case.
123
     // full screen mode and this is why we use the screen height in this case.
121
     // Need to think it further at some point and implement it properly.
124
     // Need to think it further at some point and implement it properly.
122
     if (UIUtil.isFullScreen()) {
125
     if (UIUtil.isFullScreen()) {
126
+        // eslint-disable-next-line no-param-reassign
123
         videoSpaceHeight = window.innerHeight;
127
         videoSpaceHeight = window.innerHeight;
124
     }
128
     }
125
 
129
 
126
-    let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
127
-    let verticalIndent = (videoSpaceHeight - videoHeight) / 2;
130
+    const horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
131
+    const verticalIndent = (videoSpaceHeight - videoHeight) / 2;
128
 
132
 
129
-    return { horizontalIndent, verticalIndent };
133
+    return { horizontalIndent,
134
+        verticalIndent };
130
 }
135
 }
131
 
136
 
132
 /**
137
 /**
137
  * indent
142
  * indent
138
  */
143
  */
139
 function getDesktopVideoPosition(videoWidth, videoHeight, videoSpaceWidth) {
144
 function getDesktopVideoPosition(videoWidth, videoHeight, videoSpaceWidth) {
140
-    let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
145
+    const horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
141
 
146
 
142
-    let verticalIndent = 0;// Top aligned
147
+    const verticalIndent = 0;// Top aligned
143
 
148
 
144
-    return { horizontalIndent, verticalIndent };
149
+    return { horizontalIndent,
150
+        verticalIndent };
145
 }
151
 }
146
 
152
 
147
 /**
153
 /**
149
  */
155
  */
150
 export class VideoContainer extends LargeContainer {
156
 export class VideoContainer extends LargeContainer {
151
     // FIXME: With Temasys we have to re-select everytime
157
     // FIXME: With Temasys we have to re-select everytime
152
-    get $video () {
158
+    /**
159
+     *
160
+     */
161
+    get $video() {
153
         return $('#largeVideo');
162
         return $('#largeVideo');
154
     }
163
     }
155
 
164
 
165
+    /**
166
+     *
167
+     */
156
     get $videoBackground() {
168
     get $videoBackground() {
157
         return $('#largeVideoBackground');
169
         return $('#largeVideoBackground');
158
     }
170
     }
159
 
171
 
160
-    get id () {
172
+    /**
173
+     *
174
+     */
175
+    get id() {
161
         return this.userId;
176
         return this.userId;
162
     }
177
     }
163
 
178
 
168
      * @param emitter {EventEmitter} the event emitter that will be used by
183
      * @param emitter {EventEmitter} the event emitter that will be used by
169
      * this instance.
184
      * this instance.
170
      */
185
      */
171
-    constructor (resizeContainer, emitter) {
186
+    constructor(resizeContainer, emitter) {
172
         super();
187
         super();
173
         this.stream = null;
188
         this.stream = null;
174
         this.userId = null;
189
         this.userId = null;
213
 
228
 
214
         this.avatarHeight = $('#dominantSpeakerAvatar').height();
229
         this.avatarHeight = $('#dominantSpeakerAvatar').height();
215
 
230
 
216
-        var onPlayingCallback = function (event) {
231
+        const onPlayingCallback = function(event) {
217
             if (typeof resizeContainer === 'function') {
232
             if (typeof resizeContainer === 'function') {
218
                 resizeContainer(event);
233
                 resizeContainer(event);
219
             }
234
             }
220
             this.wasVideoRendered = true;
235
             this.wasVideoRendered = true;
221
         }.bind(this);
236
         }.bind(this);
237
+
222
         // This does not work with Temasys plugin - has to be a property to be
238
         // This does not work with Temasys plugin - has to be a property to be
223
         // copied between new <object> elements
239
         // copied between new <object> elements
224
-        //this.$video.on('play', onPlay);
240
+        // this.$video.on('play', onPlay);
241
+
225
         this.$video[0].onplaying = onPlayingCallback;
242
         this.$video[0].onplaying = onPlayingCallback;
226
 
243
 
227
         /**
244
         /**
254
      * @param {boolean} enable <tt>true</tt> if the filter is to be enabled or
271
      * @param {boolean} enable <tt>true</tt> if the filter is to be enabled or
255
      * <tt>false</tt> otherwise.
272
      * <tt>false</tt> otherwise.
256
      */
273
      */
257
-    enableLocalConnectionProblemFilter (enable) {
274
+    enableLocalConnectionProblemFilter(enable) {
258
         this.$video.toggleClass('videoProblemFilter', enable);
275
         this.$video.toggleClass('videoProblemFilter', enable);
259
         this.$videoBackground.toggleClass('videoProblemFilter', enable);
276
         this.$videoBackground.toggleClass('videoProblemFilter', enable);
260
     }
277
     }
271
      * Get size of video element.
288
      * Get size of video element.
272
      * @returns {{width, height}}
289
      * @returns {{width, height}}
273
      */
290
      */
274
-    getStreamSize () {
275
-        let video = this.$video[0];
291
+    getStreamSize() {
292
+        const video = this.$video[0];
293
+
294
+
276
         return {
295
         return {
277
             width: video.videoWidth,
296
             width: video.videoWidth,
278
             height: video.videoHeight
297
             height: video.videoHeight
286
      * @returns {{availableWidth, availableHeight}}
305
      * @returns {{availableWidth, availableHeight}}
287
      */
306
      */
288
     getVideoSize(containerWidth, containerHeight) {
307
     getVideoSize(containerWidth, containerHeight) {
289
-        let { width, height } = this.getStreamSize();
308
+        const { width, height } = this.getStreamSize();
290
 
309
 
291
         if (this.stream && this.isScreenSharing()) {
310
         if (this.stream && this.isScreenSharing()) {
292
             return computeDesktopVideoSize(width,
311
             return computeDesktopVideoSize(width,
302
             interfaceConfig.VIDEO_LAYOUT_FIT);
321
             interfaceConfig.VIDEO_LAYOUT_FIT);
303
     }
322
     }
304
 
323
 
324
+    /* eslint-disable max-params */
305
     /**
325
     /**
306
      * Calculate optimal video position (offset for top left corner)
326
      * Calculate optimal video position (offset for top left corner)
307
      * for specified video size and container size.
327
      * for specified video size and container size.
311
      * @param {number} containerHeight container height
331
      * @param {number} containerHeight container height
312
      * @returns {{horizontalIndent, verticalIndent}}
332
      * @returns {{horizontalIndent, verticalIndent}}
313
      */
333
      */
314
-    getVideoPosition (width, height, containerWidth, containerHeight) {
334
+    getVideoPosition(width, height, containerWidth, containerHeight) {
335
+        /* eslint-enable max-params */
315
         if (this.stream && this.isScreenSharing()) {
336
         if (this.stream && this.isScreenSharing()) {
316
-            return getDesktopVideoPosition( width,
337
+            return getDesktopVideoPosition(width,
317
                 height,
338
                 height,
318
                 containerWidth,
339
                 containerWidth,
319
                 containerHeight);
340
                 containerHeight);
320
-        } else {
321
-            return getCameraVideoPosition(  width,
341
+        }
342
+
343
+        return getCameraVideoPosition(width,
322
                 height,
344
                 height,
323
                 containerWidth,
345
                 containerWidth,
324
                 containerHeight);
346
                 containerHeight);
325
-        }
347
+
326
     }
348
     }
327
 
349
 
328
     /**
350
     /**
346
      */
368
      */
347
     _positionParticipantStatus($element) {
369
     _positionParticipantStatus($element) {
348
         if (this.avatarDisplayed) {
370
         if (this.avatarDisplayed) {
349
-            let $avatarImage = $('#dominantSpeakerAvatar');
371
+            const $avatarImage = $('#dominantSpeakerAvatar');
372
+
350
             $element.css(
373
             $element.css(
351
                 'top',
374
                 'top',
352
                 $avatarImage.offset().top + $avatarImage.height() + 10);
375
                 $avatarImage.offset().top + $avatarImage.height() + 10);
353
         } else {
376
         } else {
354
-            let height = $element.height();
355
-            let parentHeight = $element.parent().height();
356
-            $element.css('top', (parentHeight/2) - (height/2));
377
+            const height = $element.height();
378
+            const parentHeight = $element.parent().height();
379
+
380
+            $element.css('top', (parentHeight / 2) - (height / 2));
357
         }
381
         }
358
     }
382
     }
359
 
383
 
360
-    resize (containerWidth, containerHeight, animate = false) {
384
+    /**
385
+     *
386
+     */
387
+    resize(containerWidth, containerHeight, animate = false) {
361
         // XXX Prevent TypeError: undefined is not an object when the Web
388
         // XXX Prevent TypeError: undefined is not an object when the Web
362
         // browser does not support WebRTC (yet).
389
         // browser does not support WebRTC (yet).
363
         if (this.$video.length === 0) {
390
         if (this.$video.length === 0) {
366
 
393
 
367
         this._hideVideoBackground();
394
         this._hideVideoBackground();
368
 
395
 
369
-        let [ width, height ]
396
+        const [ width, height ]
370
             = this.getVideoSize(containerWidth, containerHeight);
397
             = this.getVideoSize(containerWidth, containerHeight);
371
 
398
 
372
         if ((containerWidth > width) || (containerHeight > height)) {
399
         if ((containerWidth > width) || (containerHeight > height)) {
373
             this._showVideoBackground();
400
             this._showVideoBackground();
374
             const css
401
             const css
375
                 = containerWidth > width
402
                 = containerWidth > width
376
-                    ? { width: '100%', height: 'auto' }
377
-                    : { width: 'auto', height: '100%' };
403
+                    ? { width: '100%',
404
+                        height: 'auto' }
405
+                    : { width: 'auto',
406
+                        height: '100%' };
407
+
378
             this.$videoBackground.css(css);
408
             this.$videoBackground.css(css);
379
         }
409
         }
380
 
410
 
381
-        let { horizontalIndent, verticalIndent }
411
+        const { horizontalIndent, verticalIndent }
382
             = this.getVideoPosition(width, height,
412
             = this.getVideoPosition(width, height,
383
             containerWidth, containerHeight);
413
             containerWidth, containerHeight);
384
 
414
 
385
         // update avatar position
415
         // update avatar position
386
-        let top = containerHeight / 2 - this.avatarHeight / 4 * 3;
416
+        const top = (containerHeight / 2) - (this.avatarHeight / 4 * 3);
387
 
417
 
388
         this.$avatar.css('top', top);
418
         this.$avatar.css('top', top);
389
 
419
 
390
         this.positionRemoteStatusMessages();
420
         this.positionRemoteStatusMessages();
391
 
421
 
392
         this.$wrapper.animate({
422
         this.$wrapper.animate({
393
-            width: width,
394
-            height: height,
423
+            width,
424
+            height,
395
 
425
 
396
             top: verticalIndent,
426
             top: verticalIndent,
397
             bottom: verticalIndent,
427
             bottom: verticalIndent,
422
      * @param {JitsiTrack?} stream new stream
452
      * @param {JitsiTrack?} stream new stream
423
      * @param {string} videoType video type
453
      * @param {string} videoType video type
424
      */
454
      */
425
-    setStream (userID, stream, videoType) {
455
+    setStream(userID, stream, videoType) {
426
         this.userId = userID;
456
         this.userId = userID;
427
         if (this.stream === stream) {
457
         if (this.stream === stream) {
428
             // Handles the use case for the remote participants when the
458
             // Handles the use case for the remote participants when the
429
             // videoType is received with delay after turning on/off the
459
             // videoType is received with delay after turning on/off the
430
             // desktop sharing.
460
             // desktop sharing.
431
-            if(this.videoType !== videoType) {
461
+            if (this.videoType !== videoType) {
432
                 this.videoType = videoType;
462
                 this.videoType = videoType;
433
                 this.resizeContainer();
463
                 this.resizeContainer();
434
             }
464
             }
465
+
435
             return;
466
             return;
436
-        } else {
437
-            // The stream has changed, so the image will be lost on detach
438
-            this.wasVideoRendered = false;
439
         }
467
         }
440
 
468
 
469
+        // The stream has changed, so the image will be lost on detach
470
+        this.wasVideoRendered = false;
471
+
472
+
441
         // detach old stream
473
         // detach old stream
442
         if (this.stream) {
474
         if (this.stream) {
443
             this.stream.detach(this.$video[0]);
475
             this.stream.detach(this.$video[0]);
475
      */
507
      */
476
     setLocalFlipX(val) {
508
     setLocalFlipX(val) {
477
         this.localFlipX = val;
509
         this.localFlipX = val;
478
-        if(!this.$video || !this.stream || !this.stream.isLocal())
510
+        if (!this.$video || !this.stream || !this.stream.isLocal()) {
479
             return;
511
             return;
512
+        }
480
         this.$video.css({
513
         this.$video.css({
481
             transform: this.localFlipX ? 'scaleX(-1)' : 'none'
514
             transform: this.localFlipX ? 'scaleX(-1)' : 'none'
482
         });
515
         });
491
      * Check if current video stream is screen sharing.
524
      * Check if current video stream is screen sharing.
492
      * @returns {boolean}
525
      * @returns {boolean}
493
      */
526
      */
494
-    isScreenSharing () {
527
+    isScreenSharing() {
495
         return this.videoType === 'desktop';
528
         return this.videoType === 'desktop';
496
     }
529
     }
497
 
530
 
499
      * Show or hide user avatar.
532
      * Show or hide user avatar.
500
      * @param {boolean} show
533
      * @param {boolean} show
501
      */
534
      */
502
-    showAvatar (show) {
535
+    showAvatar(show) {
503
         // TO FIX: Video background need to be black, so that we don't have a
536
         // TO FIX: Video background need to be black, so that we don't have a
504
         // flickering effect when scrolling between videos and have the screen
537
         // flickering effect when scrolling between videos and have the screen
505
         // move to grey before going back to video. Avatars though can have the
538
         // move to grey before going back to video. Avatars though can have the
521
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
554
      * @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
522
      * the indication.
555
      * the indication.
523
      */
556
      */
524
-    showRemoteConnectionProblemIndicator (show) {
557
+    showRemoteConnectionProblemIndicator(show) {
525
         this.$video.toggleClass('remoteVideoProblemFilter', show);
558
         this.$video.toggleClass('remoteVideoProblemFilter', show);
526
         this.$videoBackground.toggleClass('remoteVideoProblemFilter', show);
559
         this.$videoBackground.toggleClass('remoteVideoProblemFilter', show);
527
 
560
 
528
         this.$avatar.toggleClass('remoteVideoProblemFilter', show);
561
         this.$avatar.toggleClass('remoteVideoProblemFilter', show);
529
     }
562
     }
530
 
563
 
531
-    // We are doing fadeOut/fadeIn animations on parent div which wraps
532
-    // largeVideo, because when Temasys plugin is in use it replaces
533
-    // <video> elements with plugin <object> tag. In Safari jQuery is
534
-    // unable to store values on this plugin object which breaks all
535
-    // animation effects performed on it directly.
536
 
564
 
537
-    show () {
565
+    /**
566
+     * We are doing fadeOut/fadeIn animations on parent div which wraps
567
+     * largeVideo, because when Temasys plugin is in use it replaces
568
+     * <video> elements with plugin <object> tag. In Safari jQuery is
569
+     * unable to store values on this plugin object which breaks all
570
+     * animation effects performed on it directly.
571
+     */
572
+    show() {
538
         // its already visible
573
         // its already visible
539
         if (this.isVisible) {
574
         if (this.isVisible) {
540
             return Promise.resolve();
575
             return Promise.resolve();
541
         }
576
         }
542
 
577
 
543
-        return new Promise((resolve) => {
578
+        return new Promise(resolve => {
544
             this.$wrapperParent.css('visibility', 'visible').fadeTo(
579
             this.$wrapperParent.css('visibility', 'visible').fadeTo(
545
                 FADE_DURATION_MS,
580
                 FADE_DURATION_MS,
546
                 1,
581
                 1,
552
         });
587
         });
553
     }
588
     }
554
 
589
 
555
-    hide () {
590
+    /**
591
+     * 
592
+     */
593
+    hide() {
556
         // as the container is hidden/replaced by another container
594
         // as the container is hidden/replaced by another container
557
         // hide its avatar
595
         // hide its avatar
558
         this.showAvatar(false);
596
         this.showAvatar(false);
597
+
559
         // its already hidden
598
         // its already hidden
560
         if (!this.isVisible) {
599
         if (!this.isVisible) {
561
             return Promise.resolve();
600
             return Promise.resolve();
562
         }
601
         }
563
 
602
 
564
-        return new Promise((resolve) => {
603
+        return new Promise(resolve => {
565
             this.$wrapperParent.fadeTo(FADE_DURATION_MS, 0, () => {
604
             this.$wrapperParent.fadeTo(FADE_DURATION_MS, 0, () => {
566
                 this.$wrapperParent.css('visibility', 'hidden');
605
                 this.$wrapperParent.css('visibility', 'hidden');
567
                 this.isVisible = false;
606
                 this.isVisible = false;
573
     /**
612
     /**
574
      * @return {boolean} switch on dominant speaker event if on stage.
613
      * @return {boolean} switch on dominant speaker event if on stage.
575
      */
614
      */
576
-    stayOnStage () {
615
+    stayOnStage() {
577
         return false;
616
         return false;
578
     }
617
     }
579
 
618
 
586
      * on the large video.
625
      * on the large video.
587
      * @returns {void}
626
      * @returns {void}
588
      */
627
      */
589
-    setLargeVideoBackground (isAvatar) {
628
+    setLargeVideoBackground(isAvatar) {
590
         $('#largeVideoContainer').css('background',
629
         $('#largeVideoContainer').css('background',
591
-            (this.videoType === VIDEO_CONTAINER_TYPE && !isAvatar)
630
+            this.videoType === VIDEO_CONTAINER_TYPE && !isAvatar
592
                 ? '#000' : interfaceConfig.DEFAULT_BACKGROUND);
631
                 ? '#000' : interfaceConfig.DEFAULT_BACKGROUND);
593
     }
632
     }
594
 
633
 
631
         // do not care. Some browsers (at this time, only Edge is known) don't
670
         // do not care. Some browsers (at this time, only Edge is known) don't
632
         // return a promise from .play(), so check before trying to catch.
671
         // return a promise from .play(), so check before trying to catch.
633
         const res = this.$videoBackground[0].play();
672
         const res = this.$videoBackground[0].play();
673
+
634
         if (typeof res !== 'undefined') {
674
         if (typeof res !== 'undefined') {
635
             res.catch(reason => logger.error(reason));
675
             res.catch(reason => logger.error(reason));
636
         }
676
         }

+ 273
- 202
modules/UI/videolayout/VideoLayout.js
File diff suppressed because it is too large
View File


+ 4
- 4
modules/URL/ConferenceUrl.js View File

1
-const logger = require("jitsi-meet-logger").getLogger(__filename);
1
+const logger = require('jitsi-meet-logger').getLogger(__filename);
2
 
2
 
3
 /**
3
 /**
4
  * The modules stores information about the URL used to start the conference and
4
  * The modules stores information about the URL used to start the conference and
24
      * from the sample URL.
24
      * from the sample URL.
25
      */
25
      */
26
     constructor(location) {
26
     constructor(location) {
27
-        logger.info("Stored original conference URL: " + location.href);
27
+        logger.info(`Stored original conference URL: ${location.href}`);
28
         logger.info(
28
         logger.info(
29
-                "Conference URL for invites: " + location.protocol + "//"
30
-                    + location.host + location.pathname);
29
+                `Conference URL for invites: ${location.protocol}//${
30
+                    location.host}${location.pathname}`);
31
     }
31
     }
32
 }
32
 }

+ 58
- 48
modules/devices/mediaDeviceHelper.js View File

1
 /* global APP, JitsiMeetJS */
1
 /* global APP, JitsiMeetJS */
2
 
2
 
3
 let currentAudioInputDevices,
3
 let currentAudioInputDevices,
4
-    currentVideoInputDevices,
5
-    currentAudioOutputDevices;
4
+    currentAudioOutputDevices,
5
+    currentVideoInputDevices;
6
 
6
 
7
 /**
7
 /**
8
  * Determines if currently selected audio output device should be changed after
8
  * Determines if currently selected audio output device should be changed after
16
         return;
16
         return;
17
     }
17
     }
18
 
18
 
19
-    let selectedAudioOutputDeviceId = APP.settings.getAudioOutputDeviceId();
20
-    let availableAudioOutputDevices = newDevices.filter(
19
+    const selectedAudioOutputDeviceId = APP.settings.getAudioOutputDeviceId();
20
+    const availableAudioOutputDevices = newDevices.filter(
21
         d => d.kind === 'audiooutput');
21
         d => d.kind === 'audiooutput');
22
 
22
 
23
     // Switch to 'default' audio output device if we don't have the selected one
23
     // Switch to 'default' audio output device if we don't have the selected one
24
     // available anymore.
24
     // available anymore.
25
-    if (selectedAudioOutputDeviceId !== 'default' &&
26
-        !availableAudioOutputDevices.find(d =>
25
+    if (selectedAudioOutputDeviceId !== 'default'
26
+        && !availableAudioOutputDevices.find(d =>
27
             d.deviceId === selectedAudioOutputDeviceId)) {
27
             d.deviceId === selectedAudioOutputDeviceId)) {
28
         return 'default';
28
         return 'default';
29
     }
29
     }
38
  *      if audio input device should not be changed.
38
  *      if audio input device should not be changed.
39
  */
39
  */
40
 function getNewAudioInputDevice(newDevices, localAudio) {
40
 function getNewAudioInputDevice(newDevices, localAudio) {
41
-    let availableAudioInputDevices = newDevices.filter(
41
+    const availableAudioInputDevices = newDevices.filter(
42
         d => d.kind === 'audioinput');
42
         d => d.kind === 'audioinput');
43
-    let selectedAudioInputDeviceId = APP.settings.getMicDeviceId();
44
-    let selectedAudioInputDevice = availableAudioInputDevices.find(
43
+    const selectedAudioInputDeviceId = APP.settings.getMicDeviceId();
44
+    const selectedAudioInputDevice = availableAudioInputDevices.find(
45
         d => d.deviceId === selectedAudioInputDeviceId);
45
         d => d.deviceId === selectedAudioInputDeviceId);
46
 
46
 
47
     // Here we handle case when no device was initially plugged, but
47
     // Here we handle case when no device was initially plugged, but
51
         // If we have new audio device and permission to use it was granted
51
         // If we have new audio device and permission to use it was granted
52
         // (label is not an empty string), then we will try to use the first
52
         // (label is not an empty string), then we will try to use the first
53
         // available device.
53
         // available device.
54
-        if (availableAudioInputDevices.length &&
55
-            availableAudioInputDevices[0].label !== '') {
54
+        if (availableAudioInputDevices.length
55
+            && availableAudioInputDevices[0].label !== '') {
56
             return availableAudioInputDevices[0].deviceId;
56
             return availableAudioInputDevices[0].deviceId;
57
         }
57
         }
58
-    } else {
58
+    } else if (selectedAudioInputDevice
59
+        && selectedAudioInputDeviceId !== localAudio.getDeviceId()) {
60
+
59
         // And here we handle case when we already have some device working,
61
         // And here we handle case when we already have some device working,
60
         // but we plug-in a "preferred" (previously selected in settings, stored
62
         // but we plug-in a "preferred" (previously selected in settings, stored
61
         // in local storage) device.
63
         // in local storage) device.
62
-        if (selectedAudioInputDevice &&
63
-            selectedAudioInputDeviceId !== localAudio.getDeviceId()) {
64
-            return selectedAudioInputDeviceId;
65
-        }
64
+        return selectedAudioInputDeviceId;
66
     }
65
     }
67
 }
66
 }
68
 
67
 
75
  *      if video input device should not be changed.
74
  *      if video input device should not be changed.
76
  */
75
  */
77
 function getNewVideoInputDevice(newDevices, localVideo) {
76
 function getNewVideoInputDevice(newDevices, localVideo) {
78
-    let availableVideoInputDevices = newDevices.filter(
77
+    const availableVideoInputDevices = newDevices.filter(
79
         d => d.kind === 'videoinput');
78
         d => d.kind === 'videoinput');
80
-    let selectedVideoInputDeviceId = APP.settings.getCameraDeviceId();
81
-    let selectedVideoInputDevice = availableVideoInputDevices.find(
79
+    const selectedVideoInputDeviceId = APP.settings.getCameraDeviceId();
80
+    const selectedVideoInputDevice = availableVideoInputDevices.find(
82
         d => d.deviceId === selectedVideoInputDeviceId);
81
         d => d.deviceId === selectedVideoInputDeviceId);
83
 
82
 
84
     // Here we handle case when no video input device was initially plugged,
83
     // Here we handle case when no video input device was initially plugged,
88
         // If we have new video device and permission to use it was granted
87
         // If we have new video device and permission to use it was granted
89
         // (label is not an empty string), then we will try to use the first
88
         // (label is not an empty string), then we will try to use the first
90
         // available device.
89
         // available device.
91
-        if (availableVideoInputDevices.length &&
92
-            availableVideoInputDevices[0].label !== '') {
90
+        if (availableVideoInputDevices.length
91
+            && availableVideoInputDevices[0].label !== '') {
93
             return availableVideoInputDevices[0].deviceId;
92
             return availableVideoInputDevices[0].deviceId;
94
         }
93
         }
95
-    } else {
94
+    } else if (selectedVideoInputDevice
95
+            && selectedVideoInputDeviceId !== localVideo.getDeviceId()) {
96
         // And here we handle case when we already have some device working,
96
         // And here we handle case when we already have some device working,
97
         // but we plug-in a "preferred" (previously selected in settings, stored
97
         // but we plug-in a "preferred" (previously selected in settings, stored
98
         // in local storage) device.
98
         // in local storage) device.
99
-        if (selectedVideoInputDevice &&
100
-            selectedVideoInputDeviceId !== localVideo.getDeviceId()) {
101
-            return selectedVideoInputDeviceId;
102
-        }
99
+        return selectedVideoInputDeviceId;
103
     }
100
     }
104
 }
101
 }
105
 
102
 
113
     getDevicesFromListByKind(devices, kind) {
110
     getDevicesFromListByKind(devices, kind) {
114
         return devices.filter(d => d.kind === kind);
111
         return devices.filter(d => d.kind === kind);
115
     },
112
     },
113
+
116
     /**
114
     /**
117
      * Stores lists of current 'audioinput', 'videoinput' and 'audiooutput'
115
      * Stores lists of current 'audioinput', 'videoinput' and 'audiooutput'
118
      * devices.
116
      * devices.
119
      * @param {MediaDeviceInfo[]} devices
117
      * @param {MediaDeviceInfo[]} devices
120
      */
118
      */
121
     setCurrentMediaDevices(devices) {
119
     setCurrentMediaDevices(devices) {
122
-        currentAudioInputDevices =
123
-            this.getDevicesFromListByKind(devices, 'audioinput');
124
-        currentVideoInputDevices =
125
-            this.getDevicesFromListByKind(devices, 'videoinput');
126
-        currentAudioOutputDevices =
127
-            this.getDevicesFromListByKind(devices, 'audiooutput');
120
+        currentAudioInputDevices
121
+            = this.getDevicesFromListByKind(devices, 'audioinput');
122
+        currentVideoInputDevices
123
+            = this.getDevicesFromListByKind(devices, 'videoinput');
124
+        currentAudioOutputDevices
125
+            = this.getDevicesFromListByKind(devices, 'audiooutput');
128
     },
126
     },
127
+
129
     /**
128
     /**
130
      * Returns lists of current 'audioinput', 'videoinput' and 'audiooutput'
129
      * Returns lists of current 'audioinput', 'videoinput' and 'audiooutput'
131
      * devices.
130
      * devices.
142
             audiooutput: currentAudioOutputDevices
141
             audiooutput: currentAudioOutputDevices
143
         };
142
         };
144
     },
143
     },
144
+
145
     /**
145
     /**
146
      * Determines if currently selected media devices should be changed after
146
      * Determines if currently selected media devices should be changed after
147
      * list of available devices has been changed.
147
      * list of available devices has been changed.
155
      *  audiooutput: (string|undefined)
155
      *  audiooutput: (string|undefined)
156
      *  }}
156
      *  }}
157
      */
157
      */
158
-    getNewMediaDevicesAfterDeviceListChanged(
158
+    getNewMediaDevicesAfterDeviceListChanged( // eslint-disable-line max-params
159
             newDevices,
159
             newDevices,
160
             isSharingScreen,
160
             isSharingScreen,
161
             localVideo,
161
             localVideo,
162
             localAudio) {
162
             localAudio) {
163
         return {
163
         return {
164
             audioinput: getNewAudioInputDevice(newDevices, localAudio),
164
             audioinput: getNewAudioInputDevice(newDevices, localAudio),
165
-            videoinput: !isSharingScreen &&
166
-                getNewVideoInputDevice(newDevices, localVideo),
165
+            videoinput: !isSharingScreen
166
+                && getNewVideoInputDevice(newDevices, localVideo),
167
             audiooutput: getNewAudioOutputDevice(newDevices)
167
             audiooutput: getNewAudioOutputDevice(newDevices)
168
         };
168
         };
169
     },
169
     },
170
+
170
     /**
171
     /**
171
      * Tries to create new local tracks for new devices obtained after device
172
      * Tries to create new local tracks for new devices obtained after device
172
      * list changed. Shows error dialog in case of failures.
173
      * list changed. Shows error dialog in case of failures.
181
             micDeviceId) {
182
             micDeviceId) {
182
         let audioTrackError;
183
         let audioTrackError;
183
         let videoTrackError;
184
         let videoTrackError;
184
-        let audioRequested = !!micDeviceId;
185
-        let videoRequested = !!cameraDeviceId;
185
+        const audioRequested = Boolean(micDeviceId);
186
+        const videoRequested = Boolean(cameraDeviceId);
186
 
187
 
187
         if (audioRequested && videoRequested) {
188
         if (audioRequested && videoRequested) {
188
             // First we try to create both audio and video tracks together.
189
             // First we try to create both audio and video tracks together.
189
             return (
190
             return (
190
                 createLocalTracks({
191
                 createLocalTracks({
191
-                    devices: ['audio', 'video'],
192
-                    cameraDeviceId: cameraDeviceId,
193
-                    micDeviceId: micDeviceId
192
+                    devices: [ 'audio', 'video' ],
193
+                    cameraDeviceId,
194
+                    micDeviceId
194
                 })
195
                 })
196
+
195
                 // If we fail to do this, try to create them separately.
197
                 // If we fail to do this, try to create them separately.
196
                 .catch(() => Promise.all([
198
                 .catch(() => Promise.all([
197
-                    createAudioTrack(false).then(([stream]) => stream),
198
-                    createVideoTrack(false).then(([stream]) => stream)
199
+                    createAudioTrack(false).then(([ stream ]) => stream),
200
+                    createVideoTrack(false).then(([ stream ]) => stream)
199
                 ]))
201
                 ]))
200
                 .then(tracks => {
202
                 .then(tracks => {
201
                     if (audioTrackError) {
203
                     if (audioTrackError) {
212
             return createVideoTrack();
214
             return createVideoTrack();
213
         } else if (audioRequested && !videoRequested) {
215
         } else if (audioRequested && !videoRequested) {
214
             return createAudioTrack();
216
             return createAudioTrack();
215
-        } else {
216
-            return Promise.resolve([]);
217
         }
217
         }
218
 
218
 
219
+        return Promise.resolve([]);
220
+
221
+        /**
222
+         *
223
+         */
219
         function createAudioTrack(showError) {
224
         function createAudioTrack(showError) {
220
             return (
225
             return (
221
                 createLocalTracks({
226
                 createLocalTracks({
222
-                    devices: ['audio'],
227
+                    devices: [ 'audio' ],
223
                     cameraDeviceId: null,
228
                     cameraDeviceId: null,
224
-                    micDeviceId: micDeviceId
229
+                    micDeviceId
225
                 })
230
                 })
226
                 .catch(err => {
231
                 .catch(err => {
227
                     audioTrackError = err;
232
                     audioTrackError = err;
228
                     showError && APP.UI.showMicErrorNotification(err);
233
                     showError && APP.UI.showMicErrorNotification(err);
234
+
229
                     return [];
235
                     return [];
230
                 }));
236
                 }));
231
         }
237
         }
232
 
238
 
239
+        /**
240
+         * 
241
+         */
233
         function createVideoTrack(showError) {
242
         function createVideoTrack(showError) {
234
             return (
243
             return (
235
                 createLocalTracks({
244
                 createLocalTracks({
236
-                    devices: ['video'],
237
-                    cameraDeviceId: cameraDeviceId,
245
+                    devices: [ 'video' ],
246
+                    cameraDeviceId,
238
                     micDeviceId: null
247
                     micDeviceId: null
239
                 })
248
                 })
240
                 .catch(err => {
249
                 .catch(err => {
241
                     videoTrackError = err;
250
                     videoTrackError = err;
242
                     showError && APP.UI.showCameraErrorNotification(err);
251
                     showError && APP.UI.showCameraErrorNotification(err);
252
+
243
                     return [];
253
                     return [];
244
                 }));
254
                 }));
245
         }
255
         }

+ 115
- 105
modules/keyboardshortcut/keyboardshortcut.js View File

11
  */
11
  */
12
 let keyboardShortcutDialog = null;
12
 let keyboardShortcutDialog = null;
13
 
13
 
14
-/**
15
- * Initialise global shortcuts.
16
- * Global shortcuts are shortcuts for features that don't have a button or
17
- * link associated with the action. In other words they represent actions
18
- * triggered _only_ with a shortcut.
19
- */
20
-function initGlobalShortcuts() {
21
-    KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
22
-        showKeyboardShortcutsPanel(false);
23
-    });
24
-
25
-    KeyboardShortcut.registerShortcut("?", null, function() {
26
-        sendEvent("shortcut.shortcut.help");
27
-        showKeyboardShortcutsPanel(true);
28
-    }, "keyboardShortcuts.toggleShortcuts");
29
-
30
-    // register SPACE shortcut in two steps to insure visibility of help message
31
-    KeyboardShortcut.registerShortcut(" ", null, function() {
32
-        sendEvent("shortcut.talk.clicked");
33
-        logger.log('Talk shortcut pressed');
34
-        APP.conference.muteAudio(true);
35
-    });
36
-    KeyboardShortcut._addShortcutToHelp("SPACE","keyboardShortcuts.pushToTalk");
37
-
38
-    if(!interfaceConfig.filmStripOnly) {
39
-        KeyboardShortcut.registerShortcut("T", null, () => {
40
-            sendEvent("shortcut.speakerStats.clicked");
41
-            APP.store.dispatch(toggleDialog(SpeakerStats, {
42
-                conference: APP.conference
43
-            }));
44
-        }, "keyboardShortcuts.showSpeakerStats");
45
-    }
46
-
47
-    /**
48
-     * FIXME: Currently focus keys are directly implemented below in onkeyup.
49
-     * They should be moved to the SmallVideo instead.
50
-     */
51
-    KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
52
-    KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
53
-}
54
-
55
 /**
14
 /**
56
  * Shows or hides the keyboard shortcuts dialog.
15
  * Shows or hides the keyboard shortcuts dialog.
57
  * @param {boolean} show whether to show or hide the dialog
16
  * @param {boolean} show whether to show or hide the dialog
60
     if (show
19
     if (show
61
             && !APP.UI.messageHandler.isDialogOpened()
20
             && !APP.UI.messageHandler.isDialogOpened()
62
             && keyboardShortcutDialog === null) {
21
             && keyboardShortcutDialog === null) {
63
-        let msg = $('#keyboard-shortcuts').html();
64
-        let buttons = { Close: true };
22
+        const msg = $('#keyboard-shortcuts').html();
23
+        const buttons = { Close: true };
65
 
24
 
66
         keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
25
         keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
67
             'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
26
             'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
75
  * Map of shortcuts. When a shortcut is registered it enters the mapping.
34
  * Map of shortcuts. When a shortcut is registered it enters the mapping.
76
  * @type {{}}
35
  * @type {{}}
77
  */
36
  */
78
-let _shortcuts = {};
37
+const _shortcuts = {};
79
 
38
 
80
 /**
39
 /**
81
  * True if the keyboard shortcuts are enabled and false if not.
40
  * True if the keyboard shortcuts are enabled and false if not.
87
  * Maps keycode to character, id of popover for given function and function.
46
  * Maps keycode to character, id of popover for given function and function.
88
  */
47
  */
89
 const KeyboardShortcut = {
48
 const KeyboardShortcut = {
90
-    init: function () {
91
-        initGlobalShortcuts();
49
+    init() {
50
+        this._initGlobalShortcuts();
92
 
51
 
93
-        var self = this;
94
-        window.onkeyup = function(e) {
95
-            if(!enabled) {
52
+        window.onkeyup = e => {
53
+            if (!enabled) {
96
                 return;
54
                 return;
97
             }
55
             }
98
-            var key = self._getKeyboardKey(e).toUpperCase();
99
-            var num = parseInt(key, 10);
100
-            if(!($(":focus").is("input[type=text]") ||
101
-                $(":focus").is("input[type=password]") ||
102
-                $(":focus").is("textarea"))) {
56
+            const key = this._getKeyboardKey(e).toUpperCase();
57
+            const num = parseInt(key, 10);
58
+
59
+            if (!($(':focus').is('input[type=text]')
60
+                || $(':focus').is('input[type=password]')
61
+                || $(':focus').is('textarea'))) {
103
                 if (_shortcuts.hasOwnProperty(key)) {
62
                 if (_shortcuts.hasOwnProperty(key)) {
104
                     _shortcuts[key].function(e);
63
                     _shortcuts[key].function(e);
105
-                }
106
-                else if (!isNaN(num) && num >= 0 && num <= 9) {
64
+                } else if (!isNaN(num) && num >= 0 && num <= 9) {
107
                     APP.UI.clickOnVideo(num);
65
                     APP.UI.clickOnVideo(num);
108
                 }
66
                 }
109
-            //esc while the smileys are visible hides them
110
-            } else if (key === "ESCAPE" &&
111
-                $('#smileysContainer').is(':visible')) {
67
+
68
+            // esc while the smileys are visible hides them
69
+            } else if (key === 'ESCAPE'
70
+                && $('#smileysContainer').is(':visible')) {
112
                 APP.UI.toggleSmileys();
71
                 APP.UI.toggleSmileys();
113
             }
72
             }
114
         };
73
         };
115
 
74
 
116
-        window.onkeydown = function(e) {
117
-            if(!enabled) {
75
+        window.onkeydown = e => {
76
+            if (!enabled) {
118
                 return;
77
                 return;
119
             }
78
             }
120
-            if(!($(":focus").is("input[type=text]") ||
121
-                $(":focus").is("input[type=password]") ||
122
-                $(":focus").is("textarea"))) {
123
-                var key = self._getKeyboardKey(e).toUpperCase();
124
-                if(key === " ") {
125
-                    if(APP.conference.isLocalAudioMuted()) {
126
-                        sendEvent("shortcut.talk.released");
79
+            if (!($(':focus').is('input[type=text]')
80
+                || $(':focus').is('input[type=password]')
81
+                || $(':focus').is('textarea'))) {
82
+                if (this._getKeyboardKey(e).toUpperCase() === ' ') {
83
+                    if (APP.conference.isLocalAudioMuted()) {
84
+                        sendEvent('shortcut.talk.released');
127
                         logger.log('Talk shortcut released');
85
                         logger.log('Talk shortcut released');
128
                         APP.conference.muteAudio(false);
86
                         APP.conference.muteAudio(false);
129
                     }
87
                     }
136
      * Enables/Disables the keyboard shortcuts.
94
      * Enables/Disables the keyboard shortcuts.
137
      * @param {boolean} value - the new value.
95
      * @param {boolean} value - the new value.
138
      */
96
      */
139
-    enable: function (value) {
97
+    enable(value) {
140
         enabled = value;
98
         enabled = value;
141
     },
99
     },
142
 
100
 
151
      * @param helpDescription the description of the shortcut that would appear
109
      * @param helpDescription the description of the shortcut that would appear
152
      * in the help menu
110
      * in the help menu
153
      */
111
      */
154
-    registerShortcut(
112
+    registerShortcut(// eslint-disable-line max-params
155
             shortcutChar,
113
             shortcutChar,
156
             shortcutAttr,
114
             shortcutAttr,
157
             exec,
115
             exec,
158
             helpDescription) {
116
             helpDescription) {
159
         _shortcuts[shortcutChar] = {
117
         _shortcuts[shortcutChar] = {
160
             character: shortcutChar,
118
             character: shortcutChar,
161
-            shortcutAttr: shortcutAttr,
119
+            shortcutAttr,
162
             function: exec
120
             function: exec
163
         };
121
         };
164
 
122
 
165
-        if (helpDescription)
123
+        if (helpDescription) {
166
             this._addShortcutToHelp(shortcutChar, helpDescription);
124
             this._addShortcutToHelp(shortcutChar, helpDescription);
125
+        }
167
     },
126
     },
168
 
127
 
169
     /**
128
     /**
172
      * @param shortcutChar unregisters the given shortcut, which means it will
131
      * @param shortcutChar unregisters the given shortcut, which means it will
173
      * no longer be usable
132
      * no longer be usable
174
      */
133
      */
175
-    unregisterShortcut: function(shortcutChar) {
134
+    unregisterShortcut(shortcutChar) {
176
         _shortcuts.remove(shortcutChar);
135
         _shortcuts.remove(shortcutChar);
177
 
136
 
178
         this._removeShortcutFromHelp(shortcutChar);
137
         this._removeShortcutFromHelp(shortcutChar);
186
      * or an empty string if the shortcutAttr is null, an empty string or not
145
      * or an empty string if the shortcutAttr is null, an empty string or not
187
      * found in the shortcut mapping
146
      * found in the shortcut mapping
188
      */
147
      */
189
-    getShortcutTooltip: function (shortcutAttr) {
190
-        if (typeof shortcutAttr === "string" && shortcutAttr.length > 0) {
191
-            for (var key in _shortcuts) {
148
+    getShortcutTooltip(shortcutAttr) {
149
+        if (typeof shortcutAttr === 'string' && shortcutAttr.length > 0) {
150
+            for (const key in _shortcuts) {
192
                 if (_shortcuts.hasOwnProperty(key)
151
                 if (_shortcuts.hasOwnProperty(key)
193
                     && _shortcuts[key].shortcutAttr
152
                     && _shortcuts[key].shortcutAttr
194
                     && _shortcuts[key].shortcutAttr === shortcutAttr) {
153
                     && _shortcuts[key].shortcutAttr === shortcutAttr) {
195
-                    return " (" + _shortcuts[key].character + ")";
154
+                    return ` (${_shortcuts[key].character})`;
196
                 }
155
                 }
197
             }
156
             }
198
         }
157
         }
199
 
158
 
200
-        return "";
159
+        return '';
201
     },
160
     },
161
+
202
     /**
162
     /**
203
      * @param e a KeyboardEvent
163
      * @param e a KeyboardEvent
204
      * @returns {string} e.key or something close if not supported
164
      * @returns {string} e.key or something close if not supported
205
      */
165
      */
206
-    _getKeyboardKey: function (e) {
207
-        if (typeof e.key === "string") {
166
+    _getKeyboardKey(e) {
167
+        if (typeof e.key === 'string') {
208
             return e.key;
168
             return e.key;
209
         }
169
         }
210
-        if (e.type === "keypress"
170
+        if (e.type === 'keypress'
211
                 && ((e.which >= 32 && e.which <= 126)
171
                 && ((e.which >= 32 && e.which <= 126)
212
-                    || (e.which >= 160 && e.which <= 255) )) {
172
+                    || (e.which >= 160 && e.which <= 255))) {
213
             return String.fromCharCode(e.which);
173
             return String.fromCharCode(e.which);
214
         }
174
         }
175
+
215
         // try to fallback (0-9A-Za-z and QWERTY keyboard)
176
         // try to fallback (0-9A-Za-z and QWERTY keyboard)
216
         switch (e.which) {
177
         switch (e.which) {
217
         case 27:
178
         case 27:
218
-            return "Escape";
179
+            return 'Escape';
219
         case 191:
180
         case 191:
220
-            return e.shiftKey ? "?" : "/";
181
+            return e.shiftKey ? '?' : '/';
221
         }
182
         }
222
-        if (e.shiftKey || e.type === "keypress") {
183
+        if (e.shiftKey || e.type === 'keypress') {
223
             return String.fromCharCode(e.which);
184
             return String.fromCharCode(e.which);
224
-        } else {
225
-            return String.fromCharCode(e.which).toLowerCase();
226
         }
185
         }
186
+
187
+        return String.fromCharCode(e.which).toLowerCase();
188
+
227
     },
189
     },
228
 
190
 
229
     /**
191
     /**
233
      * @param shortcutDescriptionKey the description of the shortcut
195
      * @param shortcutDescriptionKey the description of the shortcut
234
      * @private
196
      * @private
235
      */
197
      */
236
-    _addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
198
+    _addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
199
+
200
+        const listElement = document.createElement('li');
201
+        const itemClass = 'shortcuts-list__item';
237
 
202
 
238
-        let listElement = document.createElement("li");
239
-        let itemClass = 'shortcuts-list__item';
240
         listElement.className = itemClass;
203
         listElement.className = itemClass;
241
         listElement.id = shortcutChar;
204
         listElement.id = shortcutChar;
242
 
205
 
243
-        let spanElement = document.createElement("span");
244
-        spanElement.className = "item-action";
206
+        const spanElement = document.createElement('span');
207
+
208
+        spanElement.className = 'item-action';
209
+
210
+        const kbdElement = document.createElement('kbd');
211
+        const classes = 'aui-label regular-key';
245
 
212
 
246
-        let kbdElement = document.createElement("kbd");
247
-        let classes = 'aui-label regular-key';
248
         kbdElement.className = classes;
213
         kbdElement.className = classes;
249
         kbdElement.innerHTML = shortcutChar;
214
         kbdElement.innerHTML = shortcutChar;
250
         spanElement.appendChild(kbdElement);
215
         spanElement.appendChild(kbdElement);
251
 
216
 
252
-        let descriptionElement = document.createElement("span");
253
-        let descriptionClass = "shortcuts-list__description";
217
+        const descriptionElement = document.createElement('span');
218
+        const descriptionClass = 'shortcuts-list__description';
219
+
254
         descriptionElement.className = descriptionClass;
220
         descriptionElement.className = descriptionClass;
255
-        descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
221
+        descriptionElement.setAttribute('data-i18n', shortcutDescriptionKey);
256
         APP.translation.translateElement($(descriptionElement));
222
         APP.translation.translateElement($(descriptionElement));
257
 
223
 
258
         listElement.appendChild(spanElement);
224
         listElement.appendChild(spanElement);
259
         listElement.appendChild(descriptionElement);
225
         listElement.appendChild(descriptionElement);
260
 
226
 
261
-        let parentListElement
262
-            = document.getElementById("keyboard-shortcuts-list");
227
+        const parentListElement
228
+            = document.getElementById('keyboard-shortcuts-list');
263
 
229
 
264
-        if (parentListElement)
230
+        if (parentListElement) {
265
             parentListElement.appendChild(listElement);
231
             parentListElement.appendChild(listElement);
232
+        }
266
     },
233
     },
267
 
234
 
268
     /**
235
     /**
270
      * help dialog
237
      * help dialog
271
      * @private
238
      * @private
272
      */
239
      */
273
-    _removeShortcutFromHelp: function (shortcutChar) {
274
-        var parentListElement
275
-            = document.getElementById("keyboard-shortcuts-list");
240
+    _removeShortcutFromHelp(shortcutChar) {
241
+        const parentListElement
242
+            = document.getElementById('keyboard-shortcuts-list');
276
 
243
 
277
-        var shortcutElement = document.getElementById(shortcutChar);
244
+        const shortcutElement = document.getElementById(shortcutChar);
278
 
245
 
279
-        if (shortcutElement)
246
+        if (shortcutElement) {
280
             parentListElement.removeChild(shortcutElement);
247
             parentListElement.removeChild(shortcutElement);
248
+        }
249
+    },
250
+
251
+    /**
252
+     * Initialise global shortcuts.
253
+     * Global shortcuts are shortcuts for features that don't have a button or
254
+     * link associated with the action. In other words they represent actions
255
+     * triggered _only_ with a shortcut.
256
+     */
257
+    _initGlobalShortcuts() {
258
+        this.registerShortcut('ESCAPE', null, () => {
259
+            showKeyboardShortcutsPanel(false);
260
+        });
261
+
262
+        this.registerShortcut('?', null, () => {
263
+            sendEvent('shortcut.shortcut.help');
264
+            showKeyboardShortcutsPanel(true);
265
+        }, 'keyboardShortcuts.toggleShortcuts');
266
+
267
+        // register SPACE shortcut in two steps to insure visibility of help
268
+        // message
269
+        this.registerShortcut(' ', null, () => {
270
+            sendEvent('shortcut.talk.clicked');
271
+            logger.log('Talk shortcut pressed');
272
+            APP.conference.muteAudio(true);
273
+        });
274
+        this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
275
+
276
+        if (!interfaceConfig.filmStripOnly) {
277
+            this.registerShortcut('T', null, () => {
278
+                sendEvent('shortcut.speakerStats.clicked');
279
+                APP.store.dispatch(toggleDialog(SpeakerStats, {
280
+                    conference: APP.conference
281
+                }));
282
+            }, 'keyboardShortcuts.showSpeakerStats');
283
+        }
284
+
285
+        /**
286
+         * FIXME: Currently focus keys are directly implemented below in
287
+         * onkeyup. They should be moved to the SmallVideo instead.
288
+         */
289
+        this._addShortcutToHelp('0', 'keyboardShortcuts.focusLocal');
290
+        this._addShortcutToHelp('1-9', 'keyboardShortcuts.focusRemote');
281
     }
291
     }
282
 };
292
 };
283
 
293
 

+ 63
- 60
modules/keycode/keycode.js View File

5
  * @enum {string}
5
  * @enum {string}
6
  */
6
  */
7
 export const KEYS = {
7
 export const KEYS = {
8
-    BACKSPACE: "backspace" ,
9
-    DELETE : "delete",
10
-    RETURN : "enter",
11
-    TAB : "tab",
12
-    ESCAPE : "escape",
13
-    UP : "up",
14
-    DOWN : "down",
15
-    RIGHT : "right",
16
-    LEFT : "left",
17
-    HOME : "home",
18
-    END : "end",
19
-    PAGEUP : "pageup",
20
-    PAGEDOWN : "pagedown",
8
+    BACKSPACE: 'backspace',
9
+    DELETE: 'delete',
10
+    RETURN: 'enter',
11
+    TAB: 'tab',
12
+    ESCAPE: 'escape',
13
+    UP: 'up',
14
+    DOWN: 'down',
15
+    RIGHT: 'right',
16
+    LEFT: 'left',
17
+    HOME: 'home',
18
+    END: 'end',
19
+    PAGEUP: 'pageup',
20
+    PAGEDOWN: 'pagedown',
21
 
21
 
22
-    F1 : "f1",
23
-    F2 : "f2",
24
-    F3 : "f3",
25
-    F4 : "f4",
26
-    F5 : "f5",
27
-    F6 : "f6",
28
-    F7 : "f7",
29
-    F8 : "f8",
30
-    F9 : "f9",
31
-    F10 : "f10",
32
-    F11 : "f11",
33
-    F12 : "f12",
34
-    META : "command",
35
-    CMD_L: "command",
36
-    CMD_R: "command",
37
-    ALT : "alt",
38
-    CONTROL : "control",
39
-    SHIFT : "shift",
40
-    CAPS_LOCK: "caps_lock", //not supported by robotjs
41
-    SPACE : "space",
42
-    PRINTSCREEN : "printscreen",
43
-    INSERT : "insert",
22
+    F1: 'f1',
23
+    F2: 'f2',
24
+    F3: 'f3',
25
+    F4: 'f4',
26
+    F5: 'f5',
27
+    F6: 'f6',
28
+    F7: 'f7',
29
+    F8: 'f8',
30
+    F9: 'f9',
31
+    F10: 'f10',
32
+    F11: 'f11',
33
+    F12: 'f12',
34
+    META: 'command',
35
+    CMD_L: 'command',
36
+    CMD_R: 'command',
37
+    ALT: 'alt',
38
+    CONTROL: 'control',
39
+    SHIFT: 'shift',
40
+    CAPS_LOCK: 'caps_lock', // not supported by robotjs
41
+    SPACE: 'space',
42
+    PRINTSCREEN: 'printscreen',
43
+    INSERT: 'insert',
44
 
44
 
45
-    NUMPAD_0 : "numpad_0",
46
-    NUMPAD_1 : "numpad_1",
47
-    NUMPAD_2 : "numpad_2",
48
-    NUMPAD_3 : "numpad_3",
49
-    NUMPAD_4 : "numpad_4",
50
-    NUMPAD_5 : "numpad_5",
51
-    NUMPAD_6 : "numpad_6",
52
-    NUMPAD_7 : "numpad_7",
53
-    NUMPAD_8 : "numpad_8",
54
-    NUMPAD_9 : "numpad_9",
45
+    NUMPAD_0: 'numpad_0',
46
+    NUMPAD_1: 'numpad_1',
47
+    NUMPAD_2: 'numpad_2',
48
+    NUMPAD_3: 'numpad_3',
49
+    NUMPAD_4: 'numpad_4',
50
+    NUMPAD_5: 'numpad_5',
51
+    NUMPAD_6: 'numpad_6',
52
+    NUMPAD_7: 'numpad_7',
53
+    NUMPAD_8: 'numpad_8',
54
+    NUMPAD_9: 'numpad_9',
55
 
55
 
56
-    COMMA: ",",
56
+    COMMA: ',',
57
 
57
 
58
-    PERIOD: ".",
59
-    SEMICOLON: ";",
60
-    QUOTE: "'",
61
-    BRACKET_LEFT: "[",
62
-    BRACKET_RIGHT: "]",
63
-    BACKQUOTE: "`",
64
-    BACKSLASH: "\\",
65
-    MINUS: "-",
66
-    EQUAL: "=",
67
-    SLASH: "/"
58
+    PERIOD: '.',
59
+    SEMICOLON: ';',
60
+    QUOTE: '\'',
61
+    BRACKET_LEFT: '[',
62
+    BRACKET_RIGHT: ']',
63
+    BACKQUOTE: '`',
64
+    BACKSLASH: '\\',
65
+    MINUS: '-',
66
+    EQUAL: '=',
67
+    SLASH: '/'
68
 };
68
 };
69
 
69
 
70
+/* eslint-disable max-len */
70
 /**
71
 /**
71
  * Mapping between the key codes and keys deined in KEYS.
72
  * Mapping between the key codes and keys deined in KEYS.
72
  * The mappings are based on
73
  * The mappings are based on
73
  * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Specifications
74
  * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Specifications
74
  */
75
  */
75
-let keyCodeToKey = {
76
+/* eslint-enable max-len */
77
+const keyCodeToKey = {
76
     8: KEYS.BACKSPACE,
78
     8: KEYS.BACKSPACE,
77
     9: KEYS.TAB,
79
     9: KEYS.TAB,
78
     13: KEYS.RETURN,
80
     13: KEYS.RETURN,
141
 /**
143
 /**
142
  * Generate codes for digit keys (0-9)
144
  * Generate codes for digit keys (0-9)
143
  */
145
  */
144
-for(let i = 0; i < 10; i++) {
146
+for (let i = 0; i < 10; i++) {
145
     keyCodeToKey[i + 48] = `${i}`;
147
     keyCodeToKey[i + 48] = `${i}`;
146
 }
148
 }
147
 
149
 
148
 /**
150
 /**
149
  * Generate codes for letter keys (a-z)
151
  * Generate codes for letter keys (a-z)
150
  */
152
  */
151
-for(let i = 0; i < 26; i++) {
152
-    let keyCode = i + 65;
153
+for (let i = 0; i < 26; i++) {
154
+    const keyCode = i + 65;
155
+
153
     keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase();
156
     keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase();
154
 }
157
 }
155
 
158
 

+ 7
- 3
modules/recorder/Recorder.js View File

3
 /**
3
 /**
4
  * The (name of the) command which transports the recorder info.
4
  * The (name of the) command which transports the recorder info.
5
  */
5
  */
6
-const _USER_INFO_COMMAND = "userinfo";
6
+const _USER_INFO_COMMAND = 'userinfo';
7
 
7
 
8
 /**
8
 /**
9
  * The Recorder class is meant to take care of recorder related presence
9
  * The Recorder class is meant to take care of recorder related presence
10
  * commands.
10
  * commands.
11
  */
11
  */
12
 class Recorder {
12
 class Recorder {
13
+    /**
14
+     * Creates new recorder instance.
15
+     */
13
     constructor() {
16
     constructor() {
14
-        if (config.iAmRecorder)
17
+        if (config.iAmRecorder) {
15
             this._sendRecorderInfo();
18
             this._sendRecorderInfo();
19
+        }
16
     }
20
     }
17
 
21
 
18
     /**
22
     /**
20
      * @private
24
      * @private
21
      */
25
      */
22
     _sendRecorderInfo() {
26
     _sendRecorderInfo() {
23
-        var commands = APP.conference.commands;
27
+        const commands = APP.conference.commands;
24
 
28
 
25
         // XXX The "Follow Me" command represents a snapshot of all states
29
         // XXX The "Follow Me" command represents a snapshot of all states
26
         // which are to be followed so don't forget to removeCommand before
30
         // which are to be followed so don't forget to removeCommand before

+ 52
- 44
modules/settings/Settings.js View File

1
 /* global JitsiMeetJS */
1
 /* global JitsiMeetJS */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
2
+const logger = require('jitsi-meet-logger').getLogger(__filename);
3
 
3
 
4
 import UIUtil from '../UI/util/UIUtil';
4
 import UIUtil from '../UI/util/UIUtil';
5
 import jitsiLocalStorage from '../util/JitsiLocalStorage';
5
 import jitsiLocalStorage from '../util/JitsiLocalStorage';
7
 
7
 
8
 let avatarUrl = '';
8
 let avatarUrl = '';
9
 
9
 
10
-let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("email") || '');
11
-let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("avatarId") || '');
10
+let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem('email') || '');
11
+let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem('avatarId') || '');
12
+
12
 if (!avatarId) {
13
 if (!avatarId) {
13
     // if there is no avatar id, we generate a unique one and use it forever
14
     // if there is no avatar id, we generate a unique one and use it forever
14
     avatarId = randomHexString(32);
15
     avatarId = randomHexString(32);
15
-    jitsiLocalStorage.setItem("avatarId", avatarId);
16
+    jitsiLocalStorage.setItem('avatarId', avatarId);
16
 }
17
 }
17
 
18
 
18
-let localFlipX = JSON.parse(jitsiLocalStorage.getItem("localFlipX") || true);
19
+let localFlipX = JSON.parse(jitsiLocalStorage.getItem('localFlipX') || true);
19
 let displayName = UIUtil.unescapeHtml(
20
 let displayName = UIUtil.unescapeHtml(
20
-    jitsiLocalStorage.getItem("displayname") || '');
21
-let cameraDeviceId = jitsiLocalStorage.getItem("cameraDeviceId") || '';
22
-let micDeviceId = jitsiLocalStorage.getItem("micDeviceId") || '';
21
+    jitsiLocalStorage.getItem('displayname') || '');
22
+let cameraDeviceId = jitsiLocalStorage.getItem('cameraDeviceId') || '';
23
+let micDeviceId = jitsiLocalStorage.getItem('micDeviceId') || '';
23
 let welcomePageDisabled = JSON.parse(
24
 let welcomePageDisabled = JSON.parse(
24
-    jitsiLocalStorage.getItem("welcomePageDisabled") || false);
25
+    jitsiLocalStorage.getItem('welcomePageDisabled') || false);
25
 
26
 
26
 // Currently audio output device change is supported only in Chrome and
27
 // Currently audio output device change is supported only in Chrome and
27
 // default output always has 'default' device ID
28
 // default output always has 'default' device ID
28
-let audioOutputDeviceId = jitsiLocalStorage.getItem("audioOutputDeviceId")
29
+const audioOutputDeviceId = jitsiLocalStorage.getItem('audioOutputDeviceId')
29
     || 'default';
30
     || 'default';
30
 
31
 
31
-if (audioOutputDeviceId !==
32
-    JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
32
+if (audioOutputDeviceId
33
+    !== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
33
     JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
34
     JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
34
-        .catch((ex) => {
35
-            logger.warn('Failed to set audio output device from local ' +
36
-                'storage. Default audio output device will be used' +
37
-                'instead.', ex);
35
+        .catch(ex => {
36
+            logger.warn('Failed to set audio output device from local '
37
+                + 'storage. Default audio output device will be used'
38
+                + 'instead.', ex);
38
         });
39
         });
39
 }
40
 }
40
 
41
 
46
      * @param {string} newDisplayName unescaped display name for the local user
47
      * @param {string} newDisplayName unescaped display name for the local user
47
      * @param {boolean} disableLocalStore disables local store the display name
48
      * @param {boolean} disableLocalStore disables local store the display name
48
      */
49
      */
49
-    setDisplayName (newDisplayName, disableLocalStore) {
50
+    setDisplayName(newDisplayName, disableLocalStore) {
50
         displayName = newDisplayName;
51
         displayName = newDisplayName;
51
 
52
 
52
-        if (!disableLocalStore)
53
-            jitsiLocalStorage.setItem("displayname",
53
+        if (!disableLocalStore) {
54
+            jitsiLocalStorage.setItem('displayname',
54
                 UIUtil.escapeHtml(displayName));
55
                 UIUtil.escapeHtml(displayName));
56
+        }
55
     },
57
     },
56
 
58
 
57
     /**
59
     /**
58
      * Returns the escaped display name currently used by the user
60
      * Returns the escaped display name currently used by the user
59
      * @returns {string} currently valid user display name.
61
      * @returns {string} currently valid user display name.
60
      */
62
      */
61
-    getDisplayName: function () {
63
+    getDisplayName() {
62
         return displayName;
64
         return displayName;
63
     },
65
     },
64
 
66
 
67
      * @param {string} newEmail new email for the local user
69
      * @param {string} newEmail new email for the local user
68
      * @param {boolean} disableLocalStore disables local store the email
70
      * @param {boolean} disableLocalStore disables local store the email
69
      */
71
      */
70
-    setEmail: function (newEmail, disableLocalStore) {
72
+    setEmail(newEmail, disableLocalStore) {
71
         email = newEmail;
73
         email = newEmail;
72
 
74
 
73
-        if (!disableLocalStore)
74
-            jitsiLocalStorage.setItem("email", UIUtil.escapeHtml(newEmail));
75
+        if (!disableLocalStore) {
76
+            jitsiLocalStorage.setItem('email', UIUtil.escapeHtml(newEmail));
77
+        }
75
     },
78
     },
76
 
79
 
77
     /**
80
     /**
78
      * Returns email address of the local user.
81
      * Returns email address of the local user.
79
      * @returns {string} email
82
      * @returns {string} email
80
      */
83
      */
81
-    getEmail: function () {
84
+    getEmail() {
82
         return email;
85
         return email;
83
     },
86
     },
84
 
87
 
86
      * Returns avatar id of the local user.
89
      * Returns avatar id of the local user.
87
      * @returns {string} avatar id
90
      * @returns {string} avatar id
88
      */
91
      */
89
-    getAvatarId: function () {
92
+    getAvatarId() {
90
         return avatarId;
93
         return avatarId;
91
     },
94
     },
92
 
95
 
94
      * Sets new avatarUrl for local user and saves it to the local storage.
97
      * Sets new avatarUrl for local user and saves it to the local storage.
95
      * @param {string} newAvatarUrl new avatarUrl for the local user
98
      * @param {string} newAvatarUrl new avatarUrl for the local user
96
      */
99
      */
97
-    setAvatarUrl: function (newAvatarUrl) {
100
+    setAvatarUrl(newAvatarUrl) {
98
         avatarUrl = newAvatarUrl;
101
         avatarUrl = newAvatarUrl;
99
     },
102
     },
100
 
103
 
102
      * Returns avatarUrl address of the local user.
105
      * Returns avatarUrl address of the local user.
103
      * @returns {string} avatarUrl
106
      * @returns {string} avatarUrl
104
      */
107
      */
105
-    getAvatarUrl: function () {
108
+    getAvatarUrl() {
106
         return avatarUrl;
109
         return avatarUrl;
107
     },
110
     },
108
 
111
 
110
      * Sets new flipX state of local video and saves it to the local storage.
113
      * Sets new flipX state of local video and saves it to the local storage.
111
      * @param {string} val flipX state of local video
114
      * @param {string} val flipX state of local video
112
      */
115
      */
113
-    setLocalFlipX: function (val) {
116
+    setLocalFlipX(val) {
114
         localFlipX = val;
117
         localFlipX = val;
115
-        jitsiLocalStorage.setItem("localFlipX", val);
118
+        jitsiLocalStorage.setItem('localFlipX', val);
116
     },
119
     },
117
 
120
 
118
     /**
121
     /**
119
      * Returns flipX state of local video.
122
      * Returns flipX state of local video.
120
      * @returns {string} flipX
123
      * @returns {string} flipX
121
      */
124
      */
122
-    getLocalFlipX: function () {
125
+    getLocalFlipX() {
123
         return localFlipX;
126
         return localFlipX;
124
     },
127
     },
125
 
128
 
128
      * Empty string stands for default device.
131
      * Empty string stands for default device.
129
      * @returns {String}
132
      * @returns {String}
130
      */
133
      */
131
-    getCameraDeviceId: function () {
134
+    getCameraDeviceId() {
132
         return cameraDeviceId;
135
         return cameraDeviceId;
133
     },
136
     },
137
+
134
     /**
138
     /**
135
      * Set device id of the camera which is currently in use.
139
      * Set device id of the camera which is currently in use.
136
      * Empty string stands for default device.
140
      * Empty string stands for default device.
137
      * @param {string} newId new camera device id
141
      * @param {string} newId new camera device id
138
      * @param {boolean} whether we need to store the value
142
      * @param {boolean} whether we need to store the value
139
      */
143
      */
140
-    setCameraDeviceId: function (newId, store) {
144
+    setCameraDeviceId(newId, store) {
141
         cameraDeviceId = newId;
145
         cameraDeviceId = newId;
142
-        if (store)
143
-            jitsiLocalStorage.setItem("cameraDeviceId", newId);
146
+        if (store) {
147
+            jitsiLocalStorage.setItem('cameraDeviceId', newId);
148
+        }
144
     },
149
     },
145
 
150
 
146
     /**
151
     /**
148
      * Empty string stands for default device.
153
      * Empty string stands for default device.
149
      * @returns {String}
154
      * @returns {String}
150
      */
155
      */
151
-    getMicDeviceId: function () {
156
+    getMicDeviceId() {
152
         return micDeviceId;
157
         return micDeviceId;
153
     },
158
     },
159
+
154
     /**
160
     /**
155
      * Set device id of the microphone which is currently in use.
161
      * Set device id of the microphone which is currently in use.
156
      * Empty string stands for default device.
162
      * Empty string stands for default device.
157
      * @param {string} newId new microphone device id
163
      * @param {string} newId new microphone device id
158
      * @param {boolean} whether we need to store the value
164
      * @param {boolean} whether we need to store the value
159
      */
165
      */
160
-    setMicDeviceId: function (newId, store) {
166
+    setMicDeviceId(newId, store) {
161
         micDeviceId = newId;
167
         micDeviceId = newId;
162
-        if (store)
163
-            jitsiLocalStorage.setItem("micDeviceId", newId);
168
+        if (store) {
169
+            jitsiLocalStorage.setItem('micDeviceId', newId);
170
+        }
164
     },
171
     },
165
 
172
 
166
     /**
173
     /**
168
      * Empty string stands for default device.
175
      * Empty string stands for default device.
169
      * @returns {String}
176
      * @returns {String}
170
      */
177
      */
171
-    getAudioOutputDeviceId: function () {
178
+    getAudioOutputDeviceId() {
172
         return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
179
         return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
173
     },
180
     },
181
+
174
     /**
182
     /**
175
      * Set device id of the audio output device which is currently in use.
183
      * Set device id of the audio output device which is currently in use.
176
      * Empty string stands for default device.
184
      * Empty string stands for default device.
177
      * @param {string} newId='default' - new audio output device id
185
      * @param {string} newId='default' - new audio output device id
178
      * @returns {Promise}
186
      * @returns {Promise}
179
      */
187
      */
180
-    setAudioOutputDeviceId: function (newId = 'default') {
188
+    setAudioOutputDeviceId(newId = 'default') {
181
         return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
189
         return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
182
             .then(() =>
190
             .then(() =>
183
-                jitsiLocalStorage.setItem("audioOutputDeviceId", newId));
191
+                jitsiLocalStorage.setItem('audioOutputDeviceId', newId));
184
     },
192
     },
185
 
193
 
186
     /**
194
     /**
187
      * Check if welcome page is enabled or not.
195
      * Check if welcome page is enabled or not.
188
      * @returns {boolean}
196
      * @returns {boolean}
189
      */
197
      */
190
-    isWelcomePageEnabled () {
198
+    isWelcomePageEnabled() {
191
         return !welcomePageDisabled;
199
         return !welcomePageDisabled;
192
     },
200
     },
193
 
201
 
195
      * Enable or disable welcome page.
203
      * Enable or disable welcome page.
196
      * @param {boolean} enabled if welcome page should be enabled or not
204
      * @param {boolean} enabled if welcome page should be enabled or not
197
      */
205
      */
198
-    setWelcomePageEnabled (enabled) {
206
+    setWelcomePageEnabled(enabled) {
199
         welcomePageDisabled = !enabled;
207
         welcomePageDisabled = !enabled;
200
-        jitsiLocalStorage.setItem("welcomePageDisabled", welcomePageDisabled);
208
+        jitsiLocalStorage.setItem('welcomePageDisabled', welcomePageDisabled);
201
     }
209
     }
202
 };
210
 };

+ 24
- 2
modules/translation/translation.js View File

16
     $('[data-i18n]').localize();
16
     $('[data-i18n]').localize();
17
 }
17
 }
18
 
18
 
19
+/**
20
+ *
21
+ */
19
 class Translation {
22
 class Translation {
23
+    /**
24
+     *
25
+     */
20
     addLanguageChangedListener(listener: Function) {
26
     addLanguageChangedListener(listener: Function) {
21
         i18next.on('languageChanged', listener);
27
         i18next.on('languageChanged', listener);
22
     }
28
     }
23
 
29
 
30
+    /**
31
+     *
32
+     */
24
     generateTranslationHTML(key: string, options: Object) {
33
     generateTranslationHTML(key: string, options: Object) {
25
         const optAttr
34
         const optAttr
26
             = options ? ` data-i18n-options='${JSON.stringify(options)}'` : '';
35
             = options ? ` data-i18n-options='${JSON.stringify(options)}'` : '';
31
         return `<span data-i18n="${key}"${optAttr}>${text}</span>`;
40
         return `<span data-i18n="${key}"${optAttr}>${text}</span>`;
32
     }
41
     }
33
 
42
 
43
+    /**
44
+     *
45
+     */
34
     getCurrentLanguage() {
46
     getCurrentLanguage() {
35
         return i18next.lng();
47
         return i18next.lng();
36
     }
48
     }
37
 
49
 
50
+    /**
51
+     *
52
+     */
38
     init() {
53
     init() {
39
         jqueryI18next.init(i18next, $, { useOptionsAttr: true });
54
         jqueryI18next.init(i18next, $, { useOptionsAttr: true });
40
 
55
 
41
-        if (i18next.isInitialized)
56
+        if (i18next.isInitialized) {
42
             _onI18nInitialized();
57
             _onI18nInitialized();
43
-        else
58
+        } else {
44
             i18next.on('initialized', _onI18nInitialized);
59
             i18next.on('initialized', _onI18nInitialized);
60
+        }
45
     }
61
     }
46
 
62
 
63
+    /**
64
+     *
65
+     */
47
     setLanguage(language: string = DEFAULT_LANGUAGE) {
66
     setLanguage(language: string = DEFAULT_LANGUAGE) {
48
         i18next.setLng(language, {}, _onI18nInitialized);
67
         i18next.setLng(language, {}, _onI18nInitialized);
49
     }
68
     }
50
 
69
 
70
+    /**
71
+     * 
72
+     */
51
     translateElement(selector: Object, options: Object) {
73
     translateElement(selector: Object, options: Object) {
52
         // XXX i18next expects undefined if options are missing.
74
         // XXX i18next expects undefined if options are missing.
53
         selector.localize(options ? options : undefined);
75
         selector.localize(options ? options : undefined);

+ 1
- 0
modules/transport/PostMessageTransportBackend.js View File

65
      * transport.
65
      * transport.
66
      */
66
      */
67
     constructor({ enableLegacyFormat, postisOptions } = {}) {
67
     constructor({ enableLegacyFormat, postisOptions } = {}) {
68
+        // eslint-disable-next-line new-cap
68
         this.postis = Postis({
69
         this.postis = Postis({
69
             ...DEFAULT_POSTIS_OPTIONS,
70
             ...DEFAULT_POSTIS_OPTIONS,
70
             ...postisOptions
71
             ...postisOptions

+ 2
- 0
modules/util/JitsiLocalStorage.js View File

6
  * Dummy implementation of Storage interface with empty methods.
6
  * Dummy implementation of Storage interface with empty methods.
7
  */
7
  */
8
 class DummyLocalStorage {
8
 class DummyLocalStorage {
9
+    /* eslint-disable no-empty-function */
9
     /**
10
     /**
10
      * Empty function
11
      * Empty function
11
      */
12
      */
20
      * Empty function
21
      * Empty function
21
      */
22
      */
22
     removeItem() { }
23
     removeItem() { }
24
+    /* eslint-enable no-empty-function */
23
 }
25
 }
24
 
26
 
25
 /**
27
 /**

+ 7
- 5
modules/util/JitsiMeetLogStorage.js View File

37
             return;
37
             return;
38
         }
38
         }
39
 
39
 
40
-        let logJSON = '{"log' + this.counter + '":"\n';
40
+        let logJSON = `{"log${this.counter}":"\n`;
41
+
41
         for (let i = 0, len = logEntries.length; i < len; i++) {
42
         for (let i = 0, len = logEntries.length; i < len; i++) {
42
-            let logEntry = logEntries[i];
43
+            const logEntry = logEntries[i];
44
+
43
             if (typeof logEntry === 'object') {
45
             if (typeof logEntry === 'object') {
44
                 // Aggregated message
46
                 // Aggregated message
45
-                logJSON += '(' + logEntry.count + ') ' + logEntry.text + '\n';
47
+                logJSON += `(${logEntry.count}) ${logEntry.text}\n`;
46
             } else {
48
             } else {
47
                 // Regular message
49
                 // Regular message
48
-                logJSON += logEntry + '\n';
50
+                logJSON += `${logEntry}\n`;
49
             }
51
             }
50
         }
52
         }
51
         logJSON += '"}';
53
         logJSON += '"}';
60
         } catch (error) {
62
         } catch (error) {
61
             // NOTE console is intentional here
63
             // NOTE console is intentional here
62
             console.error(
64
             console.error(
63
-                "Failed to store the logs: ", logJSON, error);
65
+                'Failed to store the logs: ', logJSON, error);
64
         }
66
         }
65
     }
67
     }
66
 }
68
 }

+ 2
- 2
modules/util/helpers.js View File

1
-const logger = require("jitsi-meet-logger").getLogger(__filename);
1
+const logger = require('jitsi-meet-logger').getLogger(__filename);
2
 
2
 
3
 /**
3
 /**
4
  * Create deferred object.
4
  * Create deferred object.
40
  * @param e {Error} the error
40
  * @param e {Error} the error
41
  * @param msg {string} [optional] the message printed in addition to the error
41
  * @param msg {string} [optional] the message printed in addition to the error
42
  */
42
  */
43
-export function reportError(e, msg = "") {
43
+export function reportError(e, msg = '') {
44
     logger.error(msg, e);
44
     logger.error(msg, e);
45
     window.onerror && window.onerror(msg, null, null, null, e);
45
     window.onerror && window.onerror(msg, null, null, null, e);
46
 }
46
 }

+ 0
- 259
react/.eslintrc.js View File

6
         }
6
         }
7
     },
7
     },
8
     'plugins': [
8
     'plugins': [
9
-
10
-        // ESLint's rule no-duplicate-imports does not understand Flow's import
11
-        // type. Fortunately, eslint-plugin-import understands Flow's import
12
-        // type.
13
-        'import',
14
         'jsdoc',
9
         'jsdoc',
15
         'react',
10
         'react',
16
         'react-native'
11
         'react-native'
17
     ],
12
     ],
18
     'rules': {
13
     'rules': {
19
         // Possible Errors group
14
         // Possible Errors group
20
-        'no-cond-assign': 2,
21
-        'no-console': 0,
22
-        'no-constant-condition': 2,
23
-        'no-control-regex': 2,
24
-        'no-debugger': 2,
25
-        'no-dupe-args': 2,
26
-        'no-dupe-keys': 2,
27
-        'no-duplicate-case': 2,
28
-        'no-empty': 2,
29
-        'no-empty-character-class': 2,
30
-        'no-ex-assign': 2,
31
-        'no-extra-boolean-cast': 2,
32
-        'no-extra-parens': [
33
-            'error',
34
-            'all',
35
-            { 'nestedBinaryExpressions': false }
36
-        ],
37
-        'no-extra-semi': 2,
38
-        'no-func-assign': 2,
39
-        'no-inner-declarations': 2,
40
-        'no-invalid-regexp': 2,
41
-        'no-irregular-whitespace': 2,
42
-        'no-negated-in-lhs': 2,
43
-        'no-obj-calls': 2,
44
-        'no-prototype-builtins': 0,
45
-        'no-regex-spaces': 2,
46
-        'no-sparse-arrays': 2,
47
-        'no-unexpected-multiline': 2,
48
-        'no-unreachable': 2,
49
-        'no-unsafe-finally': 2,
50
-        'use-isnan': 2,
51
 
15
 
52
         // Currently, we are using both valid-jsdoc and 'jsdoc' plugin. In the
16
         // Currently, we are using both valid-jsdoc and 'jsdoc' plugin. In the
53
         // future we might stick to one as soon as it has all the features.
17
         // future we might stick to one as soon as it has all the features.
74
                 'requireReturnType': true
38
                 'requireReturnType': true
75
             }
39
             }
76
         ],
40
         ],
77
-        'valid-typeof': 2,
78
 
41
 
79
         // Best Practices group
42
         // Best Practices group
80
-        'accessor-pairs': 0,
81
-        'array-callback-return': 2,
82
-        'block-scoped-var': 0,
83
-        'complexity': 0,
84
-        'consistent-return': 0,
85
-        'curly': 2,
86
-        'default-case': 0,
87
-        'dot-location': [ 'error', 'property' ],
88
-        'dot-notation': 2,
89
-        'eqeqeq': 2,
90
-        'guard-for-in': 2,
91
-        'no-alert': 2,
92
-        'no-caller': 2,
93
-        'no-case-declarations': 2,
94
-        'no-div-regex': 0,
95
-        'no-else-return': 2,
96
-        'no-empty-function': 2,
97
-        'no-empty-pattern': 2,
98
-        'no-eq-null': 2,
99
-        'no-eval': 2,
100
-        'no-extend-native': 2,
101
-        'no-extra-bind': 2,
102
-        'no-extra-label': 2,
103
-        'no-fallthrough': 2,
104
-        'no-floating-decimal': 2,
105
-        'no-implicit-coercion': 2,
106
-        'no-implicit-globals': 2,
107
-        'no-implied-eval': 2,
108
-        'no-invalid-this': 2,
109
-        'no-iterator': 2,
110
-        'no-labels': 2,
111
-        'no-lone-blocks': 2,
112
-        'no-loop-func': 2,
113
-        'no-magic-numbers': 0,
114
-        'no-multi-spaces': 2,
115
-        'no-multi-str': 2,
116
-        'no-native-reassign': 2,
117
-        'no-new': 2,
118
-        'no-new-func': 2,
119
-        'no-new-wrappers': 2,
120
-        'no-octal': 2,
121
-        'no-octal-escape': 2,
122
-        'no-param-reassign': 2,
123
-        'no-proto': 2,
124
-        'no-redeclare': 2,
125
-        'no-return-assign': 2,
126
-        'no-script-url': 2,
127
-        'no-self-assign': 2,
128
-        'no-self-compare': 2,
129
-        'no-sequences': 2,
130
-        'no-throw-literal': 2,
131
-        'no-unmodified-loop-condition': 2,
132
-        'no-unused-expressions': [
133
-            'error',
134
-            {
135
-                'allowShortCircuit': true,
136
-                'allowTernary': true
137
-            }
138
-        ],
139
-        'no-unused-labels': 2,
140
-        'no-useless-call': 2,
141
-        'no-useless-concat': 2,
142
-        'no-useless-escape': 2,
143
-        'no-void': 2,
144
-        'no-warning-comments': 0,
145
-        'no-with': 2,
146
-        'radix': 2,
147
-        'vars-on-top': 2,
148
-        'wrap-iife': [ 'error', 'inside' ],
149
-        'yoda': 2,
150
-
151
-        // Strict Mode group
152
-        'strict': 2,
153
-
154
-        // Variables group
155
-        'init-declarations': 0,
156
-        'no-catch-shadow': 2,
157
-        'no-delete-var': 2,
158
-        'no-label-var': 2,
159
-        'no-restricted-globals': 0,
160
-        'no-shadow': 2,
161
-        'no-shadow-restricted-names': 2,
162
-        'no-undef': 2,
163
-        'no-undef-init': 2,
164
-        'no-undefined': 0,
165
-        'no-unused-vars': 2,
166
-        'no-use-before-define': [ 'error', { 'functions': false } ],
167
-
168
-        // Stylistic issues group
169
-        'array-bracket-spacing': [
170
-            'error',
171
-            'always',
172
-            { 'objectsInArrays': true }
173
-        ],
174
-        'block-spacing': [ 'error', 'always' ],
175
-        'brace-style': 2,
176
-        'camelcase': 2,
177
-        'comma-dangle': 2,
178
-        'comma-spacing': 2,
179
-        'comma-style': 2,
180
-        'computed-property-spacing': 2,
181
-        'consistent-this': [ 'error', 'self' ],
182
-        'eol-last': 2,
183
-        'func-names': 0,
184
-        'func-style': 0,
185
-        'id-blacklist': 0,
186
-        'id-length': 0,
187
-        'id-match': 0,
188
         'jsx-quotes': [ 'error', 'prefer-single' ],
43
         'jsx-quotes': [ 'error', 'prefer-single' ],
189
-        'key-spacing': 2,
190
-        'keyword-spacing': 2,
191
-        'linebreak-style': [ 'error', 'unix' ],
192
-        'lines-around-comment': [
193
-            'error',
194
-            {
195
-                'allowBlockStart': true,
196
-                'allowObjectStart': true,
197
-                'beforeBlockComment': true,
198
-                'beforeLineComment': true
199
-            }
200
-        ],
201
-        'max-depth': 2,
202
-        'max-len': [ 'error', 80 ],
203
-        'max-lines': 0,
204
-        'max-nested-callbacks': 2,
205
-        'max-params': 2,
206
-        'max-statements': 0,
207
-        'max-statements-per-line': 2,
208
-        'multiline-ternary': 0,
209
-        'new-cap': 2,
210
-        'new-parens': 2,
211
-        'newline-after-var': 2,
212
-        'newline-before-return': 2,
213
-        'newline-per-chained-call': 2,
214
-        'no-array-constructor': 2,
215
-        'no-bitwise': 2,
216
-        'no-continue': 2,
217
-        'no-inline-comments': 0,
218
-        'no-lonely-if': 2,
219
-        'no-mixed-operators': 2,
220
-        'no-mixed-spaces-and-tabs': 2,
221
-        'no-multiple-empty-lines': 2,
222
-        'no-negated-condition': 2,
223
-        'no-nested-ternary': 0,
224
-        'no-new-object': 2,
225
-        'no-plusplus': 0,
226
-        'no-restricted-syntax': 0,
227
-        'no-spaced-func': 2,
228
-        'no-tabs': 2,
229
-        'no-ternary': 0,
230
-        'no-trailing-spaces': 2,
231
-        'no-underscore-dangle': 0,
232
-        'no-unneeded-ternary': 2,
233
-        'no-whitespace-before-property': 2,
234
-        'object-curly-newline': 0,
235
-        'object-curly-spacing': [ 'error', 'always' ],
236
-        'object-property-newline': 2,
237
-        'one-var': 0,
238
-        'one-var-declaration-per-line': 0,
239
-        'operator-assignment': 0,
240
-        'operator-linebreak': [ 'error', 'before' ],
241
-        'padded-blocks': 0,
242
-        'quote-props': 0,
243
-        'quotes': [ 'error', 'single' ],
244
-        'require-jsdoc': [
245
-            'error',
246
-            {
247
-                'require': {
248
-                    'ClassDeclaration': true,
249
-                    'FunctionDeclaration': true,
250
-                    'MethodDefinition': true
251
-                }
252
-            }
253
-        ],
254
-        'semi': [ 'error', 'always' ],
255
-        'semi-spacing': 2,
256
-        'sort-vars': 2,
257
-        'space-before-blocks': 2,
258
-        'space-before-function-paren': [ 'error', 'never' ],
259
-        'space-in-parens': [ 'error', 'never' ],
260
-        'space-infix-ops': 2,
261
-        'space-unary-ops': 2,
262
-        'spaced-comment': 2,
263
-        'unicode-bom': 0,
264
-        'wrap-regex': 0,
265
 
44
 
266
         // ES6 group rules
45
         // ES6 group rules
267
-        'arrow-body-style': [
268
-            'error',
269
-            'as-needed',
270
-            { requireReturnForObjectLiteral: true }
271
-        ],
272
-        'arrow-parens': [ 'error', 'as-needed' ],
273
-        'arrow-spacing': 2,
274
-        'constructor-super': 2,
275
-        'generator-star-spacing': 2,
276
-        'no-class-assign': 2,
277
-        'no-confusing-arrow': 2,
278
-        'no-const-assign': 2,
279
-        'no-dupe-class-members': 2,
280
-        'no-new-symbol': 2,
281
-        'no-restricted-imports': 0,
282
-        'no-this-before-super': 2,
283
-        'no-useless-computed-key': 2,
284
-        'no-useless-constructor': 2,
285
-        'no-useless-rename': 2,
286
-        'no-var': 2,
287
-        'object-shorthand': [
288
-            'error',
289
-            'always',
290
-            { 'avoidQuotes': true }
291
-        ],
292
-        'prefer-arrow-callback': [ 'error', { 'allowNamedFunctions': true } ],
293
-        'prefer-const': 2,
294
-        'prefer-reflect': 0,
295
-        'prefer-rest-params': 2,
296
-        'prefer-spread': 2,
297
-        'prefer-template': 2,
298
-        'require-yield': 2,
299
-        'rest-spread-spacing': 2,
300
-        'sort-imports': 0,
301
-        'template-curly-spacing': 2,
302
-        'yield-star-spacing': 2,
303
-
304
-        'import/no-duplicates': 2,
305
 
46
 
306
         // JsDoc plugin rules group. The following rules are in addition to
47
         // JsDoc plugin rules group. The following rules are in addition to
307
         // valid-jsdoc rule.
48
         // valid-jsdoc rule.

+ 52
- 43
service/UI/UIEvents.js View File

1
 export default {
1
 export default {
2
-    NICKNAME_CHANGED: "UI.nickname_changed",
3
-    SELECTED_ENDPOINT: "UI.selected_endpoint",
4
-    PINNED_ENDPOINT: "UI.pinned_endpoint",
2
+    NICKNAME_CHANGED: 'UI.nickname_changed',
3
+    SELECTED_ENDPOINT: 'UI.selected_endpoint',
4
+    PINNED_ENDPOINT: 'UI.pinned_endpoint',
5
+
5
     /**
6
     /**
6
      * Notifies that local user created text message.
7
      * Notifies that local user created text message.
7
      */
8
      */
8
-    MESSAGE_CREATED: "UI.message_created",
9
+    MESSAGE_CREATED: 'UI.message_created',
10
+
9
     /**
11
     /**
10
      * Notifies that local user changed language.
12
      * Notifies that local user changed language.
11
      */
13
      */
12
-    LANG_CHANGED: "UI.lang_changed",
14
+    LANG_CHANGED: 'UI.lang_changed',
15
+
13
     /**
16
     /**
14
      * Notifies that local user changed email.
17
      * Notifies that local user changed email.
15
      */
18
      */
16
-    EMAIL_CHANGED: "UI.email_changed",
19
+    EMAIL_CHANGED: 'UI.email_changed',
20
+
17
     /**
21
     /**
18
      * Notifies that "start muted" settings changed.
22
      * Notifies that "start muted" settings changed.
19
      */
23
      */
20
-    START_MUTED_CHANGED: "UI.start_muted_changed",
21
-    AUDIO_MUTED: "UI.audio_muted",
22
-    VIDEO_MUTED: "UI.video_muted",
23
-    VIDEO_UNMUTING_WHILE_AUDIO_ONLY: "UI.video_unmuting_while_audio_only",
24
-    ETHERPAD_CLICKED: "UI.etherpad_clicked",
25
-    SHARED_VIDEO_CLICKED: "UI.start_shared_video",
24
+    START_MUTED_CHANGED: 'UI.start_muted_changed',
25
+    AUDIO_MUTED: 'UI.audio_muted',
26
+    VIDEO_MUTED: 'UI.video_muted',
27
+    VIDEO_UNMUTING_WHILE_AUDIO_ONLY: 'UI.video_unmuting_while_audio_only',
28
+    ETHERPAD_CLICKED: 'UI.etherpad_clicked',
29
+    SHARED_VIDEO_CLICKED: 'UI.start_shared_video',
30
+
26
     /**
31
     /**
27
      * Updates shared video with params: url, state, time(optional)
32
      * Updates shared video with params: url, state, time(optional)
28
      * Where url is the video link, state is stop/start/pause and time is the
33
      * Where url is the video link, state is stop/start/pause and time is the
29
      * current video playing time.
34
      * current video playing time.
30
      */
35
      */
31
-    UPDATE_SHARED_VIDEO: "UI.update_shared_video",
32
-    USER_KICKED: "UI.user_kicked",
33
-    REMOTE_AUDIO_MUTED: "UI.remote_audio_muted",
34
-    TOGGLE_FULLSCREEN: "UI.toogle_fullscreen",
35
-    FULLSCREEN_TOGGLED: "UI.fullscreen_toggled",
36
-    AUTH_CLICKED: "UI.auth_clicked",
36
+    UPDATE_SHARED_VIDEO: 'UI.update_shared_video',
37
+    USER_KICKED: 'UI.user_kicked',
38
+    REMOTE_AUDIO_MUTED: 'UI.remote_audio_muted',
39
+    TOGGLE_FULLSCREEN: 'UI.toogle_fullscreen',
40
+    FULLSCREEN_TOGGLED: 'UI.fullscreen_toggled',
41
+    AUTH_CLICKED: 'UI.auth_clicked',
42
+
37
     /**
43
     /**
38
      * Notifies that the audio only mode was toggled.
44
      * Notifies that the audio only mode was toggled.
39
      */
45
      */
40
-    TOGGLE_AUDIO_ONLY: "UI.toggle_audioonly",
41
-    TOGGLE_CHAT: "UI.toggle_chat",
42
-    TOGGLE_SETTINGS: "UI.toggle_settings",
43
-    TOGGLE_CONTACT_LIST: "UI.toggle_contact_list",
46
+    TOGGLE_AUDIO_ONLY: 'UI.toggle_audioonly',
47
+    TOGGLE_CHAT: 'UI.toggle_chat',
48
+    TOGGLE_SETTINGS: 'UI.toggle_settings',
49
+    TOGGLE_CONTACT_LIST: 'UI.toggle_contact_list',
50
+
44
     /**
51
     /**
45
      * Notifies that the profile toolbar button has been clicked.
52
      * Notifies that the profile toolbar button has been clicked.
46
      */
53
      */
47
-    TOGGLE_PROFILE: "UI.toggle_profile",
54
+    TOGGLE_PROFILE: 'UI.toggle_profile',
55
+
48
     /**
56
     /**
49
      * Notifies that a command to toggle the filmstrip has been issued. The
57
      * Notifies that a command to toggle the filmstrip has been issued. The
50
      * event may optionally specify a {Boolean} (primitive) value to assign to
58
      * event may optionally specify a {Boolean} (primitive) value to assign to
56
      *
64
      *
57
      * @see {TOGGLED_FILMSTRIP}
65
      * @see {TOGGLED_FILMSTRIP}
58
      */
66
      */
59
-    TOGGLE_FILMSTRIP: "UI.toggle_filmstrip",
67
+    TOGGLE_FILMSTRIP: 'UI.toggle_filmstrip',
68
+
60
     /**
69
     /**
61
      * Notifies that the filmstrip was (actually) toggled. The event supplies a
70
      * Notifies that the filmstrip was (actually) toggled. The event supplies a
62
      * {Boolean} (primitive) value indicating the visibility of the filmstrip
71
      * {Boolean} (primitive) value indicating the visibility of the filmstrip
64
      *
73
      *
65
      * @see {TOGGLE_FILMSTRIP}
74
      * @see {TOGGLE_FILMSTRIP}
66
      */
75
      */
67
-    TOGGLED_FILMSTRIP: "UI.toggled_filmstrip",
76
+    TOGGLED_FILMSTRIP: 'UI.toggled_filmstrip',
68
 
77
 
69
-    TOGGLE_SCREENSHARING: "UI.toggle_screensharing",
70
-    TOGGLED_SHARED_DOCUMENT: "UI.toggled_shared_document",
71
-    CONTACT_CLICKED: "UI.contact_clicked",
72
-    HANGUP: "UI.hangup",
73
-    LOGOUT: "UI.logout",
74
-    RECORDING_TOGGLED: "UI.recording_toggled",
75
-    SUBJECT_CHANGED: "UI.subject_changed",
76
-    VIDEO_DEVICE_CHANGED: "UI.video_device_changed",
77
-    AUDIO_DEVICE_CHANGED: "UI.audio_device_changed",
78
-    AUDIO_OUTPUT_DEVICE_CHANGED: "UI.audio_output_device_changed",
78
+    TOGGLE_SCREENSHARING: 'UI.toggle_screensharing',
79
+    TOGGLED_SHARED_DOCUMENT: 'UI.toggled_shared_document',
80
+    CONTACT_CLICKED: 'UI.contact_clicked',
81
+    HANGUP: 'UI.hangup',
82
+    LOGOUT: 'UI.logout',
83
+    RECORDING_TOGGLED: 'UI.recording_toggled',
84
+    SUBJECT_CHANGED: 'UI.subject_changed',
85
+    VIDEO_DEVICE_CHANGED: 'UI.video_device_changed',
86
+    AUDIO_DEVICE_CHANGED: 'UI.audio_device_changed',
87
+    AUDIO_OUTPUT_DEVICE_CHANGED: 'UI.audio_output_device_changed',
79
 
88
 
80
     /**
89
     /**
81
      * Notifies interested listeners that the follow-me feature is enabled or
90
      * Notifies interested listeners that the follow-me feature is enabled or
82
      * disabled.
91
      * disabled.
83
      */
92
      */
84
-    FOLLOW_ME_ENABLED: "UI.follow_me_enabled",
93
+    FOLLOW_ME_ENABLED: 'UI.follow_me_enabled',
85
 
94
 
86
     /**
95
     /**
87
      * Notifies that flipX property of the local video is changed.
96
      * Notifies that flipX property of the local video is changed.
88
      */
97
      */
89
-    LOCAL_FLIPX_CHANGED: "UI.local_flipx_changed",
98
+    LOCAL_FLIPX_CHANGED: 'UI.local_flipx_changed',
90
 
99
 
91
     // An event which indicates that the resolution of a remote video has
100
     // An event which indicates that the resolution of a remote video has
92
     // changed.
101
     // changed.
93
-    RESOLUTION_CHANGED: "UI.resolution_changed",
102
+    RESOLUTION_CHANGED: 'UI.resolution_changed',
94
 
103
 
95
     /**
104
     /**
96
      * Notifies that the button "Cancel" is pressed on the dialog for
105
      * Notifies that the button "Cancel" is pressed on the dialog for
97
      * external extension installation.
106
      * external extension installation.
98
      */
107
      */
99
-    EXTERNAL_INSTALLATION_CANCELED: "UI.external_installation_canceled",
108
+    EXTERNAL_INSTALLATION_CANCELED: 'UI.external_installation_canceled',
100
 
109
 
101
     /**
110
     /**
102
      * Notifies that the side toolbar container has been toggled. The actual
111
      * Notifies that the side toolbar container has been toggled. The actual
103
      * event must contain the identifier of the container that has been toggled
112
      * event must contain the identifier of the container that has been toggled
104
      * and information about toggle on or off.
113
      * and information about toggle on or off.
105
      */
114
      */
106
-    SIDE_TOOLBAR_CONTAINER_TOGGLED: "UI.side_container_toggled",
115
+    SIDE_TOOLBAR_CONTAINER_TOGGLED: 'UI.side_container_toggled',
107
 
116
 
108
     /**
117
     /**
109
      * Notifies that the raise hand has been changed.
118
      * Notifies that the raise hand has been changed.
110
      */
119
      */
111
-    LOCAL_RAISE_HAND_CHANGED: "UI.local_raise_hand_changed",
120
+    LOCAL_RAISE_HAND_CHANGED: 'UI.local_raise_hand_changed',
112
 
121
 
113
     /**
122
     /**
114
      * Notifies that the avatar is displayed or not on the largeVideo.
123
      * Notifies that the avatar is displayed or not on the largeVideo.
115
      */
124
      */
116
-    LARGE_VIDEO_AVATAR_VISIBLE: "UI.large_video_avatar_visible",
125
+    LARGE_VIDEO_AVATAR_VISIBLE: 'UI.large_video_avatar_visible',
117
 
126
 
118
     /**
127
     /**
119
      * Notifies that the displayed particpant id on the largeVideo is changed.
128
      * Notifies that the displayed particpant id on the largeVideo is changed.
120
      */
129
      */
121
-    LARGE_VIDEO_ID_CHANGED: "UI.large_video_id_changed"
130
+    LARGE_VIDEO_ID_CHANGED: 'UI.large_video_id_changed'
122
 };
131
 };

+ 18
- 18
service/remotecontrol/Constants.js View File

2
  * The value for the "var" attribute of feature tag in disco-info packets.
2
  * The value for the "var" attribute of feature tag in disco-info packets.
3
  */
3
  */
4
 export const DISCO_REMOTE_CONTROL_FEATURE
4
 export const DISCO_REMOTE_CONTROL_FEATURE
5
-    = "http://jitsi.org/meet/remotecontrol";
5
+    = 'http://jitsi.org/meet/remotecontrol';
6
 
6
 
7
 /**
7
 /**
8
  * Types of remote-control events.
8
  * Types of remote-control events.
10
   * @enum {string}
10
   * @enum {string}
11
  */
11
  */
12
 export const EVENTS = {
12
 export const EVENTS = {
13
-    mousemove: "mousemove",
14
-    mousedown: "mousedown",
15
-    mouseup: "mouseup",
16
-    mousedblclick: "mousedblclick",
17
-    mousescroll: "mousescroll",
18
-    keydown: "keydown",
19
-    keyup: "keyup",
20
-    permissions: "permissions",
21
-    start: "start",
22
-    stop: "stop",
23
-    supported: "supported"
13
+    mousemove: 'mousemove',
14
+    mousedown: 'mousedown',
15
+    mouseup: 'mouseup',
16
+    mousedblclick: 'mousedblclick',
17
+    mousescroll: 'mousescroll',
18
+    keydown: 'keydown',
19
+    keyup: 'keyup',
20
+    permissions: 'permissions',
21
+    start: 'start',
22
+    stop: 'stop',
23
+    supported: 'supported'
24
 };
24
 };
25
 
25
 
26
 /**
26
 /**
29
   * @enum {string}
29
   * @enum {string}
30
  */
30
  */
31
 export const REQUESTS = {
31
 export const REQUESTS = {
32
-    start: "start"
32
+    start: 'start'
33
 };
33
 };
34
 
34
 
35
 /**
35
 /**
38
  * @enum {string}
38
  * @enum {string}
39
  */
39
  */
40
 export const PERMISSIONS_ACTIONS = {
40
 export const PERMISSIONS_ACTIONS = {
41
-    request: "request",
42
-    grant: "grant",
43
-    deny: "deny",
44
-    error: "error"
41
+    request: 'request',
42
+    grant: 'grant',
43
+    deny: 'deny',
44
+    error: 'error'
45
 };
45
 };
46
 
46
 
47
 /**
47
 /**
48
  * The type of remote control messages.
48
  * The type of remote control messages.
49
  */
49
  */
50
-export const REMOTE_CONTROL_MESSAGE_NAME = "remote-control";
50
+export const REMOTE_CONTROL_MESSAGE_NAME = 'remote-control';
51
 
51
 
52
 /**
52
 /**
53
  * The remote control event.
53
  * The remote control event.

+ 22
- 18
static/close.js View File

1
 /* global interfaceConfig */
1
 /* global interfaceConfig */
2
-//list of tips
3
-var hints = [
4
-    "You can pin participants by clicking on their thumbnails.",// jshint ignore:line
5
-    "You can tell others you have something to say by using the \"Raise Hand\" feature",// jshint ignore:line
6
-    "You can learn about key shortcuts by pressing Shift+?",// jshint ignore:line
7
-    "You can learn more about the state of everyone's connection by hovering on the bars in their thumbnail",// jshint ignore:line
8
-    "You can hide all thumbnails by using the button in the bottom right corner"// jshint ignore:line
2
+// list of tips
3
+const hints = [
4
+    'You can pin participants by clicking on their thumbnails.',
5
+    'You can tell others you have something to say by using the "Raise Hand" '
6
+        + 'feature',
7
+    'You can learn about key shortcuts by pressing Shift+?',
8
+    'You can learn more about the state of everyone\'s connection by hovering '
9
+        + 'on the bars in their thumbnail',
10
+    'You can hide all thumbnails by using the button in the bottom right corner'
9
 ];
11
 ];
10
 
12
 
11
 /**
13
 /**
13
  *
15
  *
14
  * @return {string} the hint message.
16
  * @return {string} the hint message.
15
  */
17
  */
16
-function getHint(){
17
-    var l = hints.length - 1;
18
-    var n = Math.round(Math.random() * l);
18
+function getHint() {
19
+    const l = hints.length - 1;
20
+    const n = Math.round(Math.random() * l);
19
 
21
 
20
     return hints[n];
22
     return hints[n];
21
 }
23
 }
27
  * @param id {string} element identificator
29
  * @param id {string} element identificator
28
  * @param msg {string} text message
30
  * @param msg {string} text message
29
  */
31
  */
30
-// eslint-disable-next-line no-unused-vars
31
-function insertTextMsg(id, msg){
32
-    var el = document.getElementById(id);
32
+function insertTextMsg(id, msg) {
33
+    const el = document.getElementById(id);
33
 
34
 
34
-    if (el)
35
+    if (el) {
35
         el.innerHTML = msg;
36
         el.innerHTML = msg;
37
+    }
36
 }
38
 }
37
 
39
 
38
 /**
40
 /**
39
  * Sets the hint and thanks messages. Will be executed on load event.
41
  * Sets the hint and thanks messages. Will be executed on load event.
40
  */
42
  */
41
 function onLoad() {
43
 function onLoad() {
42
-    //Works only for close2.html because close.html doesn't have this element.
44
+    // Works only for close2.html because close.html doesn't have this element.
43
     insertTextMsg('thanksMessage',
45
     insertTextMsg('thanksMessage',
44
-        'Thank you for using ' + interfaceConfig.APP_NAME);
46
+        `Thank you for using ${interfaceConfig.APP_NAME}`);
45
 
47
 
46
     // If there is a setting show a special message only for the guests
48
     // If there is a setting show a special message only for the guests
47
     if (interfaceConfig.CLOSE_PAGE_GUEST_HINT) {
49
     if (interfaceConfig.CLOSE_PAGE_GUEST_HINT) {
48
-        if ( window.sessionStorage.getItem('guest') === 'true' ) {
49
-            var element = document.getElementById('hintQuestion');
50
+        if (window.sessionStorage.getItem('guest') === 'true') {
51
+            const element = document.getElementById('hintQuestion');
52
+
50
             element.classList.add('hide');
53
             element.classList.add('hide');
51
             insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
54
             insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
55
+
52
             return;
56
             return;
53
         }
57
         }
54
     }
58
     }

+ 16
- 9
webpack.config.js View File

3
 const process = require('process');
3
 const process = require('process');
4
 const webpack = require('webpack');
4
 const webpack = require('webpack');
5
 
5
 
6
-const aui_css = `${__dirname}/node_modules/@atlassian/aui/dist/aui/css/`;
6
+const auiCSS = `${__dirname}/node_modules/@atlassian/aui/dist/aui/css/`;
7
 
7
 
8
 /**
8
 /**
9
  * The URL of the Jitsi Meet deployment to be proxy to in the context of
9
  * The URL of the Jitsi Meet deployment to be proxy to in the context of
15
 const minimize
15
 const minimize
16
     = process.argv.indexOf('-p') !== -1
16
     = process.argv.indexOf('-p') !== -1
17
         || process.argv.indexOf('--optimize-minimize') !== -1;
17
         || process.argv.indexOf('--optimize-minimize') !== -1;
18
+
19
+// eslint-disable-next-line camelcase
18
 const node_modules = `${__dirname}/node_modules/`;
20
 const node_modules = `${__dirname}/node_modules/`;
19
 const plugins = [
21
 const plugins = [
20
     new webpack.LoaderOptionsPlugin({
22
     new webpack.LoaderOptionsPlugin({
62
         rules: [ {
64
         rules: [ {
63
             // Transpile ES2015 (aka ES6) to ES5. Accept the JSX syntax by React
65
             // Transpile ES2015 (aka ES6) to ES5. Accept the JSX syntax by React
64
             // as well.
66
             // as well.
65
-
66
-            exclude: node_modules,
67
+            exclude: node_modules, // eslint-disable-line camelcase
67
             loader: 'babel-loader',
68
             loader: 'babel-loader',
68
             options: {
69
             options: {
69
                 // XXX The require.resolve bellow solves failures to locate the
70
                 // XXX The require.resolve bellow solves failures to locate the
113
             // Emit the static assets of AUI such as images that are referenced
114
             // Emit the static assets of AUI such as images that are referenced
114
             // by CSS into the output path.
115
             // by CSS into the output path.
115
 
116
 
116
-            include: aui_css,
117
+            include: auiCSS,
117
             loader: 'file-loader',
118
             loader: 'file-loader',
118
             options: {
119
             options: {
119
-                context: aui_css,
120
+                context: auiCSS,
120
                 name: '[path][name].[ext]'
121
                 name: '[path][name].[ext]'
121
             },
122
             },
122
             test: /\.(gif|png|svg)$/
123
             test: /\.(gif|png|svg)$/
210
     const configs = module.exports;
211
     const configs = module.exports;
211
 
212
 
212
     /* eslint-disable indent */
213
     /* eslint-disable indent */
214
+    let formattedPath = path;
213
 
215
 
214
     if ((Array.isArray(configs) ? configs : Array(configs)).some(c => {
216
     if ((Array.isArray(configs) ? configs : Array(configs)).some(c => {
215
-                if (path.startsWith(c.output.publicPath)) {
217
+                if (formattedPath.startsWith(c.output.publicPath)) {
216
                     if (!minimize) {
218
                     if (!minimize) {
217
                         // Since webpack-dev-server is serving non-minimized
219
                         // Since webpack-dev-server is serving non-minimized
218
                         // artifacts, serve them even if the minimized ones are
220
                         // artifacts, serve them even if the minimized ones are
220
                         Object.keys(c.entry).some(e => {
222
                         Object.keys(c.entry).some(e => {
221
                             const name = `${e}.min.js`;
223
                             const name = `${e}.min.js`;
222
 
224
 
223
-                            if (path.indexOf(name) !== -1) {
224
-                                path = path.replace(name, `${e}.js`);
225
+                            if (formattedPath.indexOf(name) !== -1) {
226
+                                formattedPath
227
+                                    = formattedPath.replace(name, `${e}.js`);
225
 
228
 
226
                                 return true;
229
                                 return true;
227
                             }
230
                             }
231
+
232
+                            return false;
228
                         });
233
                         });
229
                     }
234
                     }
230
 
235
 
231
                     return true;
236
                     return true;
232
                 }
237
                 }
238
+
239
+                return false;
233
             })) {
240
             })) {
234
-        return path;
241
+        return formattedPath;
235
     }
242
     }
236
 
243
 
237
     /* eslint-enable indent */
244
     /* eslint-enable indent */

Loading…
Cancel
Save