瀏覽代碼

feat(eslint): Enable for non react files

master
hristoterezov 7 年之前
父節點
當前提交
969f5d67ab
共有 55 個檔案被更改,包括 3599 行新增2698 行删除
  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 查看文件

@@ -23,9 +23,157 @@ module.exports = {
23 23
         'sourceType': 'module'
24 24
     },
25 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 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 177
         'indent': [
30 178
             'error',
31 179
             4,
@@ -43,19 +191,121 @@ module.exports = {
43 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 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 查看文件

@@ -1,11 +1,11 @@
1 1
 /**
2 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 7
  * Notifies interested parties that desktop sharing enable/disable state is
8 8
  * changed.
9 9
  */
10 10
 export const DESKTOP_SHARING_ENABLED_CHANGED
11
-    = "conference.desktop_sharing_enabled_changed";
11
+    = 'conference.desktop_sharing_enabled_changed';

+ 36
- 29
analytics.js 查看文件

@@ -1,38 +1,45 @@
1 1
 /* global ga */
2 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
文件差異過大導致無法顯示
查看文件


+ 55
- 50
config.js 查看文件

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

@@ -13,7 +13,7 @@ import {
13 13
     JitsiConnectionEvents
14 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 19
  * Checks if we have data to use attach instead of connect. If we have the data
@@ -27,26 +27,31 @@ const logger = require("jitsi-meet-logger").getLogger(__filename);
27 27
  * @param {string} [roomName] the name of the conference.
28 28
  */
29 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 33
         // When connection optimization is not deployed or enabled the default
33 34
         // value will be window.XMPPAttachInfo.status = "error"
34 35
         // If the connection optimization is deployed and enabled and there is
35 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 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 47
             connection.attach(attachOptions);
44 48
             delete window.XMPPAttachInfo.data;
45 49
         } else {
46
-            connection.connect({id, password});
50
+            connection.connect({ id,
51
+                password });
47 52
         }
48 53
     } else {
49
-        APP.connect.status = "ready";
54
+        APP.connect.status = 'ready';
50 55
         APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
51 56
             id, password, connection);
52 57
     }
@@ -64,15 +69,15 @@ function connect(id, password, roomName) {
64 69
     const connectionConfig = Object.assign({}, config);
65 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 75
         = new JitsiMeetJS.JitsiConnection(
71 76
             null,
72 77
             jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
73 78
             connectionConfig);
74 79
 
75
-    return new Promise(function (resolve, reject) {
80
+    return new Promise((resolve, reject) => {
76 81
         connection.addEventListener(
77 82
             JitsiConnectionEvents.CONNECTION_ESTABLISHED,
78 83
             handleConnectionEstablished);
@@ -83,6 +88,9 @@ function connect(id, password, roomName) {
83 88
             JitsiConnectionEvents.CONNECTION_FAILED,
84 89
             connectionFailedHandler);
85 90
 
91
+        /**
92
+         *
93
+         */
86 94
         function connectionFailedHandler(error, message, credentials) {
87 95
             APP.store.dispatch(
88 96
                 connectionFailed(connection, error, message, credentials));
@@ -94,6 +102,9 @@ function connect(id, password, roomName) {
94 102
             }
95 103
         }
96 104
 
105
+        /**
106
+         *
107
+         */
97 108
         function unsubscribe() {
98 109
             connection.removeEventListener(
99 110
                 JitsiConnectionEvents.CONNECTION_ESTABLISHED,
@@ -103,15 +114,21 @@ function connect(id, password, roomName) {
103 114
                 handleConnectionFailed);
104 115
         }
105 116
 
117
+        /**
118
+         *
119
+         */
106 120
         function handleConnectionEstablished() {
107 121
             APP.store.dispatch(connectionEstablished(connection));
108 122
             unsubscribe();
109 123
             resolve(connection);
110 124
         }
111 125
 
126
+        /**
127
+         *
128
+         */
112 129
         function handleConnectionFailed(err) {
113 130
             unsubscribe();
114
-            logger.error("CONNECTION FAILED:", err);
131
+            logger.error('CONNECTION FAILED:', err);
115 132
             reject(err);
116 133
         }
117 134
 
@@ -132,17 +149,17 @@ function connect(id, password, roomName) {
132 149
  *
133 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 158
     if (usernameOverride && usernameOverride.length > 0) {
142
-        id = usernameOverride;
159
+        id = usernameOverride; // eslint-disable-line no-param-reassign
143 160
     }
144 161
     if (passwordOverride && passwordOverride.length > 0) {
145
-        password = passwordOverride;
162
+        password = passwordOverride; // eslint-disable-line no-param-reassign
146 163
     }
147 164
 
148 165
     return connect(id, password, roomName).catch(err => {

+ 2
- 2
index.html 查看文件

@@ -72,9 +72,9 @@
72 72
                         + "font-size: medium;"
73 73
                         + "font-weight: 400;"
74 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 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 78
                         + "<br/><br/> "
79 79
                         + "<div id='moreInfo' style='"
80 80
                         + "display: none;'>" + "Missing " + fileRef

+ 32
- 20
interface_config.js 查看文件

@@ -1,7 +1,9 @@
1
-var interfaceConfig = { // eslint-disable-line no-unused-vars
1
+/* eslint-disable no-unused-vars, no-var, max-len */
2
+var interfaceConfig = {
2 3
     // TO FIX: this needs to be handled from SASS variables. There are some
3 4
     // methods allowing to use variables both in css and js.
4 5
     DEFAULT_BACKGROUND: '#474747',
6
+
5 7
     /**
6 8
      * In case the desktop sharing is disabled through the config the button
7 9
      * will not be hidden, but displayed as disabled with this text us as
@@ -10,45 +12,53 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
10 12
     DESKTOP_SHARING_BUTTON_DISABLED_TOOLTIP: null,
11 13
     INITIAL_TOOLBAR_TIMEOUT: 20000,
12 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 17
     SHOW_JITSI_WATERMARK: true,
16
-    JITSI_WATERMARK_LINK: "https://jitsi.org",
18
+    JITSI_WATERMARK_LINK: 'https://jitsi.org',
19
+
17 20
     // if watermark is disabled by default, it can be shown only for guests
18 21
     SHOW_WATERMARK_FOR_GUESTS: true,
19 22
     SHOW_BRAND_WATERMARK: false,
20
-    BRAND_WATERMARK_LINK: "",
23
+    BRAND_WATERMARK_LINK: '',
21 24
     SHOW_POWERED_BY: false,
22 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 28
     INVITATION_POWERED_BY: true,
29
+
26 30
     /**
27 31
      * If we should show authentication block in profile
28 32
      */
29 33
     AUTHENTICATION_ENABLE: true,
34
+
30 35
     /**
31 36
      * the toolbar buttons line is intentionally left in one line, to be able
32 37
      * to easily override values or remove them using regex
33 38
      */
34 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 48
      * Main Toolbar Buttons
41 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 55
     // Determines how the video would fit the screen. 'both' would fit the whole
47 56
     // screen, 'height' would fit the original video height to the height of the
48 57
     // screen, 'width' would fit the original video width to the width of the
49 58
     // screen respecting ratio.
50 59
     VIDEO_LAYOUT_FIT: 'both',
51 60
     SHOW_CONTACTLIST_AVATARS: true,
61
+
52 62
     /**
53 63
      * Whether to only show the filmstrip (and hide the toolbar).
54 64
      */
@@ -59,11 +69,12 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
59 69
      */
60 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 73
     CLOSE_PAGE_GUEST_HINT: false,
64 74
     RANDOM_AVATAR_URL_PREFIX: false,
65 75
     RANDOM_AVATAR_URL_SUFFIX: false,
66 76
     FILM_STRIP_MAX_HEIGHT: 120,
77
+
67 78
     // Enables feedback star animation.
68 79
     ENABLE_FEEDBACK_ANIMATION: false,
69 80
     DISABLE_FOCUS_INDICATOR: false,
@@ -76,13 +87,13 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
76 87
      * @type {boolean}
77 88
      */
78 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 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 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 99
      * Whether the mobile app Jitsi Meet is to be promoted to participants
@@ -131,3 +142,4 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
131 142
      */
132 143
     // ADD_PEOPLE_APP_NAME: ""
133 144
 };
145
+/* eslint-enable no-unused-vars, no-var, max-len */

+ 9
- 4
logging_config.js 查看文件

@@ -1,10 +1,15 @@
1
+/* eslint-disable no-unused-vars, no-var */
1 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 5
     defaultLogLevel: 'trace',
6
+
5 7
     // Option to disable LogCollector (which stores the logs on CallStats)
6
-    //disableLogCollector: true,
8
+    // disableLogCollector: true,
9
+
7 10
     // Logging level adjustments for verbose modules:
8 11
     'modules/xmpp/strophe.util.js': 'log',
9 12
     'modules/statistics/CallStats.js': 'info'
10
-};
13
+};
14
+
15
+/* eslint-enable no-unused-vars, no-var */

+ 109
- 62
modules/FollowMe.js 查看文件

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

+ 228
- 203
modules/UI/UI.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
modules/UI/UIErrors.js 查看文件

@@ -7,4 +7,4 @@
7 7
  *
8 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 查看文件

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

+ 87
- 66
modules/UI/authentication/AuthHandler.js 查看文件

@@ -9,14 +9,14 @@ import UIUtil from '../util/UIUtil';
9 9
 
10 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 14
 let externalAuthWindow;
15 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 20
     = JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
21 21
 
22 22
 /**
@@ -26,23 +26,25 @@ let getTokenAuthUrl
26 26
  * @param {JitsiConference} room
27 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 30
     if (externalAuthWindow) {
31 31
         externalAuthWindow.focus();
32
+
32 33
         return;
33 34
     }
34 35
     if (room.isJoined()) {
35 36
         let getUrl;
37
+
36 38
         if (isTokenAuthEnabled) {
37 39
             getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
38 40
             initJWTTokenListener(room);
39 41
         } else {
40 42
             getUrl = room.getExternalAuthUrl(true);
41 43
         }
42
-        getUrl.then(function (url) {
44
+        getUrl.then(url => {
43 45
             externalAuthWindow = LoginDialog.showExternalAuthDialog(
44 46
                 url,
45
-                function () {
47
+                () => {
46 48
                     externalAuthWindow = null;
47 49
                     if (!isTokenAuthEnabled) {
48 50
                         room.join(lockPassword);
@@ -50,14 +52,10 @@ function doExternalAuth (room, lockPassword) {
50 52
                 }
51 53
             );
52 54
         });
55
+    } else if (isTokenAuthEnabled) {
56
+        redirectToTokenAuthService(room.getName());
53 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,61 +75,80 @@ function redirectToTokenAuthService(roomName) {
77 75
  * @param room the name fo the conference room.
78 76
  */
79 77
 function initJWTTokenListener(room) {
80
-    var listener = function ({ data, source }) {
78
+    /**
79
+     *
80
+     */
81
+    function listener({ data, source }) {
81 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 86
             return;
85 87
         }
86 88
 
87 89
         let jwt;
88 90
 
89 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 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 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 150
     if (window.addEventListener) {
134
-        window.addEventListener("message", listener, false);
151
+        window.addEventListener('message', listener, false);
135 152
     }
136 153
 }
137 154
 
@@ -183,7 +200,7 @@ function doXmppAuth(room, lockPassword) {
183 200
  * @param {JitsiConference} room
184 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 204
     if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
188 205
         doExternalAuth(room, lockPassword);
189 206
     } else {
@@ -198,10 +215,10 @@ function authenticate (room, lockPassword) {
198 215
  * @param {string} [lockPassword] password to use if the conference is locked
199 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 220
         room.room.moderator.logout(resolve);
204
-    }).then(function (url) {
221
+    }).then(url => {
205 222
         // de-authenticate conference on the fly
206 223
         if (room.isJoined()) {
207 224
             room.join();
@@ -241,14 +258,17 @@ function closeAuth() {
241 258
     }
242 259
 }
243 260
 
261
+/**
262
+ *
263
+ */
244 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 269
                     authDialog.close();
250 270
                     resolve(connection);
251
-                }, function (err) {
271
+                }, err => {
252 272
                     if (err === JitsiConnectionErrors.PASSWORD_REQUIRED) {
253 273
                         authDialog.displayError(err);
254 274
                     } else {
@@ -275,9 +295,10 @@ function requestAuth(roomName, connect) {
275 295
     if (isTokenAuthEnabled) {
276 296
         // This Promise never resolves as user gets redirected to another URL
277 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 304
 export default {

+ 48
- 38
modules/UI/authentication/LoginDialog.js 查看文件

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

+ 17
- 13
modules/UI/avatar/Avatar.js 查看文件

@@ -25,7 +25,7 @@
25 25
 
26 26
 import { getAvatarURL } from '../../../react/features/base/participants';
27 27
 
28
-let users = {};
28
+const users = {};
29 29
 
30 30
 export default {
31 31
     /**
@@ -34,17 +34,19 @@ export default {
34 34
      * @param prop {string} name of the prop
35 35
      * @param val {string} value to be set
36 36
      */
37
-    _setUserProp: function (id, prop, val) {
37
+    _setUserProp(id, prop, val) {
38 38
         // FIXME: Fixes the issue with not be able to return avatar for the
39 39
         // local user when the conference has been left. Maybe there is beter
40 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 45
             return;
46
-        if(!users[id])
46
+        }
47
+        if (!users[id]) {
47 48
             users[id] = {};
49
+        }
48 50
         users[id][prop] = val;
49 51
     },
50 52
 
@@ -54,8 +56,8 @@ export default {
54 56
      * @param id id of the user
55 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,8 +66,8 @@ export default {
64 66
      * @param id id of the user
65 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,8 +75,8 @@ export default {
73 75
      * @param id id of the user
74 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,10 +84,12 @@ export default {
82 84
      * identified by its id.
83 85
      * @param {string} userId user id
84 86
      */
85
-    getAvatarUrl: function (userId) {
87
+    getAvatarUrl(userId) {
86 88
         let user;
89
+
87 90
         if (!userId || APP.conference.isLocalId(userId)) {
88 91
             user = users.local;
92
+            // eslint-disable-next-line no-param-reassign
89 93
             userId = APP.conference.getMyUserId();
90 94
         } else {
91 95
             user = users[userId];

+ 81
- 43
modules/UI/etherpad/Etherpad.js 查看文件

@@ -1,8 +1,8 @@
1 1
 /* global $ */
2 2
 
3
-import VideoLayout from "../videolayout/VideoLayout";
3
+import VideoLayout from '../videolayout/VideoLayout';
4 4
 import LargeContainer from '../videolayout/LargeContainer';
5
-import UIEvents from "../../../service/UI/UIEvents";
5
+import UIEvents from '../../../service/UI/UIEvents';
6 6
 import Filmstrip from '../videolayout/Filmstrip';
7 7
 
8 8
 /**
@@ -15,14 +15,21 @@ const options = $.param({
15 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 31
         evt.initMouseEvent(
25
-            "mousemove",
32
+            'mousemove',
26 33
             true, // bubbles
27 34
             false, // not cancelable
28 35
             window,
@@ -46,27 +53,30 @@ function bubbleIframeMouseMove(iframe){
46 53
  * Default Etherpad frame width.
47 54
  */
48 55
 const DEFAULT_WIDTH = 640;
56
+
49 57
 /**
50 58
  * Default Etherpad frame height.
51 59
  */
52 60
 const DEFAULT_HEIGHT = 480;
53 61
 
54
-const ETHERPAD_CONTAINER_TYPE = "etherpad";
62
+const ETHERPAD_CONTAINER_TYPE = 'etherpad';
55 63
 
56 64
 /**
57 65
  * Container for Etherpad iframe.
58 66
  */
59 67
 class Etherpad extends LargeContainer {
60
-
61
-    constructor (domain, name) {
68
+    /**
69
+     * Creates new Etherpad object
70
+     */
71
+    constructor(domain, name) {
62 72
         super();
63 73
 
64 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 78
         iframe.frameBorder = 0;
69
-        iframe.scrolling = "no";
79
+        iframe.scrolling = 'no';
70 80
         iframe.width = DEFAULT_WIDTH;
71 81
         iframe.height = DEFAULT_HEIGHT;
72 82
         iframe.setAttribute('style', 'visibility: hidden;');
@@ -77,15 +87,17 @@ class Etherpad extends LargeContainer {
77 87
             document.domain = document.domain;
78 88
             bubbleIframeMouseMove(iframe);
79 89
 
80
-            setTimeout(function() {
90
+            setTimeout(() => {
81 91
                 const doc = iframe.contentDocument;
82 92
 
83 93
                 // the iframes inside of the etherpad are
84 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 97
                 bubbleIframeMouseMove(outer);
87 98
 
88
-                const inner = doc.getElementsByName("ace_inner")[0];
99
+                const inner = doc.getElementsByName('ace_inner')[0];
100
+
89 101
                 bubbleIframeMouseMove(inner);
90 102
             }, 2000);
91 103
         };
@@ -93,47 +105,64 @@ class Etherpad extends LargeContainer {
93 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 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 138
         const $iframe = $(this.iframe);
114 139
         const $container = $(this.container);
115
-        let self = this;
140
+        const self = this;
116 141
 
117 142
         return new Promise(resolve => {
118
-            $iframe.fadeIn(300, function () {
143
+            $iframe.fadeIn(300, () => {
119 144
                 self.bodyBackground = document.body.style.background;
120 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 148
                 resolve();
124 149
             });
125 150
         });
126 151
     }
127 152
 
128
-    hide () {
153
+    /**
154
+     *
155
+     */
156
+    hide() {
129 157
         const $iframe = $(this.iframe);
130 158
         const $container = $(this.container);
159
+
131 160
         document.body.style.background = this.bodyBackground;
132 161
 
133 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 166
                 resolve();
138 167
             });
139 168
         });
@@ -142,7 +171,7 @@ class Etherpad extends LargeContainer {
142 171
     /**
143 172
      * @return {boolean} do not switch on dominant speaker event if on stage.
144 173
      */
145
-    stayOnStage () {
174
+    stayOnStage() {
146 175
         return true;
147 176
     }
148 177
 }
@@ -151,9 +180,12 @@ class Etherpad extends LargeContainer {
151 180
  * Manager of the Etherpad frame.
152 181
  */
153 182
 export default class EtherpadManager {
154
-    constructor (domain, name, eventEmitter) {
183
+    /**
184
+     *
185
+     */
186
+    constructor(domain, name, eventEmitter) {
155 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 191
         this.domain = domain;
@@ -162,10 +194,16 @@ export default class EtherpadManager {
162 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 207
     isVisible() {
170 208
         return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
171 209
     }
@@ -173,7 +211,7 @@ export default class EtherpadManager {
173 211
     /**
174 212
      * Create new Etherpad frame.
175 213
      */
176
-    openEtherpad () {
214
+    openEtherpad() {
177 215
         this.etherpad = new Etherpad(this.domain, this.name);
178 216
         VideoLayout.addLargeVideoContainer(
179 217
             ETHERPAD_CONTAINER_TYPE,
@@ -185,12 +223,12 @@ export default class EtherpadManager {
185 223
      * Toggle Etherpad frame visibility.
186 224
      * Open new Etherpad frame if there is no Etherpad frame yet.
187 225
      */
188
-    toggleEtherpad () {
226
+    toggleEtherpad() {
189 227
         if (!this.isOpen) {
190 228
             this.openEtherpad();
191 229
         }
192 230
 
193
-        let isVisible = this.isVisible();
231
+        const isVisible = this.isVisible();
194 232
 
195 233
         VideoLayout.showLargeVideoContainer(
196 234
             ETHERPAD_CONTAINER_TYPE, !isVisible);

+ 97
- 75
modules/UI/recording/Recording.js 查看文件

@@ -14,9 +14,9 @@
14 14
  * See the License for the specific language governing permissions and
15 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 20
 import UIUtil from '../util/UIUtil';
21 21
 import VideoLayout from '../videolayout/VideoLayout';
22 22
 
@@ -84,7 +84,7 @@ let dialog = null;
84 84
  */
85 85
 function _isRecordingButtonEnabled() {
86 86
     return (
87
-        interfaceConfig.TOOLBAR_BUTTONS.indexOf("recording") !== -1
87
+        interfaceConfig.TOOLBAR_BUTTONS.indexOf('recording') !== -1
88 88
             && config.enableRecording
89 89
             && APP.conference.isRecordingSupported());
90 90
 }
@@ -95,69 +95,75 @@ function _isRecordingButtonEnabled() {
95 95
  */
96 96
 function _requestLiveStreamId() {
97 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 100
     const startStreamingButton
101
-        = APP.translation.generateTranslationHTML("dialog.startLiveStreaming");
101
+        = APP.translation.generateTranslationHTML('dialog.startLiveStreaming');
102 102
     const streamIdRequired
103 103
         = APP.translation.generateTranslationHTML(
104
-            "liveStreaming.streamIdRequired");
104
+            'liveStreaming.streamIdRequired');
105 105
     const streamIdHelp
106 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 110
         dialog = APP.UI.messageHandler.openDialogWithStates({
111 111
             state0: {
112
-                titleKey: "dialog.liveStreaming",
112
+                titleKey: 'dialog.liveStreaming',
113 113
                 html:
114 114
                     `<input  class="input-control"
115 115
                     name="streamId" type="text"
116 116
                     data-i18n="[placeholder]dialog.streamKey"
117 117
                     autofocus><div style="text-align: right">
118 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 122
                 persistent: false,
123 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 129
                 focus: ':input:first',
128 130
                 defaultButton: 1,
129
-                submit: function (e, v, m, f) {
131
+                submit(e, v, m, f) { // eslint-disable-line max-params
130 132
                     e.preventDefault();
131 133
 
132 134
                     if (v) {
133 135
                         if (f.streamId && f.streamId.length > 0) {
134 136
                             resolve(UIUtil.escapeHtml(f.streamId));
135 137
                             dialog.close();
138
+
136 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 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 154
             state1: {
151
-                titleKey: "dialog.liveStreaming",
155
+                titleKey: 'dialog.liveStreaming',
152 156
                 html: streamIdRequired,
153 157
                 persistent: false,
154 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 164
                 focus: ':input:first',
159 165
                 defaultButton: 1,
160
-                submit: function (e, v) {
166
+                submit(e, v) {
161 167
                     e.preventDefault();
162 168
                     if (v === 0) {
163 169
                         reject(APP.UI.messageHandler.CANCEL);
@@ -168,7 +174,7 @@ function _requestLiveStreamId() {
168 174
                 }
169 175
             }
170 176
         }, {
171
-            close: function () {
177
+            close() {
172 178
                 dialog = null;
173 179
             }
174 180
         });
@@ -180,26 +186,29 @@ function _requestLiveStreamId() {
180 186
  * @returns {Promise}
181 187
  */
182 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 192
                 data-i18n="[placeholder]dialog.token"
187 193
                 class="input-control"
188 194
                 autofocus>`
189
-    );
190
-    return new Promise(function (resolve, reject) {
195
+
196
+    ;
197
+
198
+
199
+    return new Promise((resolve, reject) => {
191 200
         dialog = APP.UI.messageHandler.openTwoButtonDialog({
192 201
             titleKey,
193 202
             msgString,
194 203
             leftButtonKey: 'dialog.Save',
195
-            submitFunction: function (e, v, m, f) {
204
+            submitFunction(e, v, m, f) { // eslint-disable-line max-params
196 205
                 if (v && f.recordingToken) {
197 206
                     resolve(UIUtil.escapeHtml(f.recordingToken));
198 207
                 } else {
199 208
                     reject(APP.UI.messageHandler.CANCEL);
200 209
                 }
201 210
             },
202
-            closeFunction: function () {
211
+            closeFunction() {
203 212
                 dialog = null;
204 213
             },
205 214
             focus: ':input:first'
@@ -215,18 +224,18 @@ function _requestRecordingToken() {
215 224
  * @private
216 225
  */
217 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 241
     return new Promise((resolve, reject) => {
@@ -248,7 +257,10 @@ function _showStopRecordingPrompt(recordingType) {
248 257
  * @returns {boolean} true if the condition is met or false otherwise.
249 258
  */
250 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,7 +268,7 @@ function isStartingStatus(status) {
256 268
  * @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
257 269
  * updateRecordingUI, checkAutoRecord}}
258 270
  */
259
-var Recording = {
271
+const Recording = {
260 272
     /**
261 273
      * Initializes the recording UI.
262 274
      */
@@ -267,11 +279,10 @@ var Recording = {
267 279
         this.updateRecordingState(APP.conference.getRecordingState());
268 280
 
269 281
         if (recordingType === 'jibri') {
270
-            this.baseClass = "fa fa-play-circle";
282
+            this.baseClass = 'fa fa-play-circle';
271 283
             Object.assign(this, STREAMING_TRANSLATION_KEYS);
272
-        }
273
-        else {
274
-            this.baseClass = "icon-recEnable";
284
+        } else {
285
+            this.baseClass = 'icon-recEnable';
275 286
             Object.assign(this, RECORDING_TRANSLATION_KEYS);
276 287
         }
277 288
 
@@ -301,7 +312,7 @@ var Recording = {
301 312
         const selector = $('#toolbar_button_record');
302 313
 
303 314
         selector.addClass(this.baseClass);
304
-        selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
315
+        selector.attr('data-i18n', `[content]${this.recordingButtonTooltip}`);
305 316
         APP.translation.translateElement(selector);
306 317
     },
307 318
 
@@ -310,8 +321,8 @@ var Recording = {
310 321
      * @param show {true} to show the recording button, {false} to hide it
311 322
      */
312 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 327
         UIUtil.setVisible(id, shouldShow);
317 328
     },
@@ -322,12 +333,14 @@ var Recording = {
322 333
      */
323 334
     updateRecordingState(recordingState) {
324 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 337
             return;
338
+        }
327 339
 
328 340
         // If there's no state change, we ignore the update.
329
-        if (!recordingState || this.currentState === recordingState)
341
+        if (!recordingState || this.currentState === recordingState) {
330 342
             return;
343
+        }
331 344
 
332 345
         this.updateRecordingUI(recordingState);
333 346
     },
@@ -338,7 +351,8 @@ var Recording = {
338 351
      */
339 352
     updateRecordingUI(recordingState) {
340 353
 
341
-        let oldState = this.currentState;
354
+        const oldState = this.currentState;
355
+
342 356
         this.currentState = recordingState;
343 357
 
344 358
         let labelDisplayConfiguration;
@@ -366,6 +380,7 @@ var Recording = {
366 380
             // We don't want UI changes if this is an availability change.
367 381
             if (oldState !== JitsiRecordingStatus.ON && !wasInStartingStatus) {
368 382
                 APP.store.dispatch(updateRecordingState({ recordingState }));
383
+
369 384
                 return;
370 385
             }
371 386
 
@@ -378,7 +393,7 @@ var Recording = {
378 393
 
379 394
             this._setToolbarButtonToggled(false);
380 395
 
381
-            setTimeout(function(){
396
+            setTimeout(() => {
382 397
                 APP.store.dispatch(hideRecordingLabel());
383 398
             }, 5000);
384 399
 
@@ -408,7 +423,8 @@ var Recording = {
408 423
         }
409 424
 
410 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 428
         default: {
413 429
             labelDisplayConfiguration = null;
414 430
         }
@@ -450,42 +466,48 @@ var Recording = {
450 466
                     this.eventEmitter.emit(UIEvents.RECORDING_TOGGLED);
451 467
                     sendEvent('recording.stopped');
452 468
                 },
453
-                () => {});
469
+                () => {}); // eslint-disable-line no-empty-function
454 470
             break;
455 471
         }
456 472
         case JitsiRecordingStatus.AVAILABLE:
457 473
         case JitsiRecordingStatus.OFF: {
458
-            if (this.recordingType === 'jibri')
459
-                _requestLiveStreamId().then(streamId => {
474
+            if (this.recordingType === 'jibri') {
475
+                _requestLiveStreamId()
476
+                .then(streamId => {
460 477
                     this.eventEmitter.emit(
461 478
                         UIEvents.RECORDING_TOGGLED,
462 479
                         { streamId });
463 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 484
                         sendEvent('recording.canceled');
485
+                    } else {
486
+                        logger.error(reason);
487
+                    }
469 488
                 });
470
-            else {
489
+            } else {
471 490
                 if (this.predefinedToken) {
472 491
                     this.eventEmitter.emit(
473 492
                         UIEvents.RECORDING_TOGGLED,
474 493
                         { token: this.predefinedToken });
475 494
                     sendEvent('recording.started');
495
+
476 496
                     return;
477 497
                 }
478 498
 
479
-                _requestRecordingToken().then((token) => {
499
+                _requestRecordingToken().then(token => {
480 500
                     this.eventEmitter.emit(
481 501
                         UIEvents.RECORDING_TOGGLED,
482 502
                         { token });
483 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 507
                         sendEvent('recording.canceled');
508
+                    } else {
509
+                        logger.error(reason);
510
+                    }
489 511
                 });
490 512
             }
491 513
             break;
@@ -521,7 +543,7 @@ var Recording = {
521 543
      * or not
522 544
      */
523 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 查看文件

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

+ 25
- 16
modules/UI/shared_video/SharedVideoThumb.js 查看文件

@@ -1,15 +1,17 @@
1 1
 /* global $ */
2 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 10
     this.id = url;
9 11
 
10 12
     this.url = url;
11 13
     this.setVideoType(videoType);
12
-    this.videoSpanId = "sharedVideoContainer";
14
+    this.videoSpanId = 'sharedVideoContainer';
13 15
     this.container = this.createContainer(this.videoSpanId);
14 16
     this.$container = $(this.container);
15 17
     this.container.onclick = this.videoClick.bind(this);
@@ -23,42 +25,48 @@ SharedVideoThumb.prototype.constructor = SharedVideoThumb;
23 25
 /**
24 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 37
     container.id = spanId;
34 38
     container.className = 'videocontainer';
35 39
 
36 40
     // add the avatar
37
-    var avatar = document.createElement('img');
41
+    const avatar = document.createElement('img');
42
+
38 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 45
     container.appendChild(avatar);
41 46
 
42 47
     const displayNameContainer = document.createElement('div');
48
+
43 49
     displayNameContainer.className = 'displayNameContainer';
44 50
     container.appendChild(displayNameContainer);
45 51
 
46
-    var remotes = document.getElementById('filmstripRemoteVideosContainer');
52
+    const remotes = document.getElementById('filmstripRemoteVideosContainer');
53
+
54
+
47 55
     return remotes.appendChild(container);
48 56
 };
49 57
 
50 58
 /**
51 59
  * The thumb click handler.
52 60
  */
53
-SharedVideoThumb.prototype.videoClick = function () {
61
+SharedVideoThumb.prototype.videoClick = function() {
54 62
     this.VideoLayout.handleVideoThumbClicked(this.url);
55 63
 };
56 64
 
57 65
 /**
58 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 71
     // Make sure that the large video is updated if are removing its
64 72
     // corresponding small video.
@@ -75,8 +83,9 @@ SharedVideoThumb.prototype.remove = function () {
75 83
  */
76 84
 SharedVideoThumb.prototype.setDisplayName = function(displayName) {
77 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 89
         return;
81 90
     }
82 91
 

+ 48
- 30
modules/UI/side_pannels/SideContainerToggler.js 查看文件

@@ -1,5 +1,5 @@
1 1
 /* global $ */
2
-import UIEvents from "../../../service/UI/UIEvents";
2
+import UIEvents from '../../../service/UI/UIEvents';
3 3
 
4 4
 /**
5 5
  * Handles open and close of the extended toolbar side panel
@@ -19,22 +19,28 @@ const SideContainerToggler = {
19 19
         // We may not have a side toolbar container, for example, in
20 20
         // filmstrip-only mode.
21 21
         const sideToolbarContainer
22
-            = document.getElementById("sideToolbarContainer");
22
+            = document.getElementById('sideToolbarContainer');
23 23
 
24
-        if (!sideToolbarContainer)
24
+        if (!sideToolbarContainer) {
25 25
             return;
26
+        }
26 27
 
27 28
         // Adds a listener for the animationend event that would take care of
28 29
         // hiding all internal containers when the extendedToolbarPanel is
29 30
         // closed.
30 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 39
                             SideContainerToggler.hideInnerContainer($(this));
40
+                        }
41
+                        /* eslint-enable no-invalid-this */
37 42
                     });
43
+                }
38 44
             },
39 45
             false);
40 46
     },
@@ -46,21 +52,26 @@ const SideContainerToggler = {
46 52
      * toggle
47 53
      */
48 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 58
         if (isSelectorVisible) {
53 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 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 73
                 this.show();
74
+            }
64 75
 
65 76
             this.showInnerContainer(elementSelector);
66 77
         }
@@ -71,7 +82,7 @@ const SideContainerToggler = {
71 82
      * otherwise returns {false}.
72 83
      */
73 84
     isVisible() {
74
-        return $("#sideToolbarContainer").hasClass("slideInExt");
85
+        return $('#sideToolbarContainer').hasClass('slideInExt');
75 86
     },
76 87
 
77 88
     /**
@@ -79,24 +90,27 @@ const SideContainerToggler = {
79 90
      * {false} otherwise.
80 91
      */
81 92
     isHovered() {
82
-        return $("#sideToolbarContainer:hover").length > 0;
93
+        return $('#sideToolbarContainer:hover').length > 0;
83 94
     },
84 95
 
85 96
     /**
86 97
      * Hides the side toolbar panel with a slide out animation.
87 98
      */
88 99
     hide() {
89
-        $("#sideToolbarContainer")
90
-            .removeClass("slideInExt").addClass("slideOutExt");
100
+        $('#sideToolbarContainer')
101
+            .removeClass('slideInExt')
102
+.addClass('slideOutExt');
91 103
     },
92 104
 
93 105
     /**
94 106
      * Shows the side toolbar panel with a slide in animation.
95 107
      */
96 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,7 +120,7 @@ const SideContainerToggler = {
106 120
      * element to hide
107 121
      */
108 122
     hideInnerContainer(containerSelector) {
109
-        containerSelector.removeClass("show").addClass("hide");
123
+        containerSelector.removeClass('show').addClass('hide');
110 124
 
111 125
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
112 126
             containerSelector.attr('id'), false);
@@ -124,12 +138,16 @@ const SideContainerToggler = {
124 138
         // If we quickly show a container, while another one is animating
125 139
         // and animation never ends, so we do not really hide the first one and
126 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 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 152
         this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
135 153
             containerSelector.attr('id'), true);
@@ -138,9 +156,9 @@ const SideContainerToggler = {
138 156
     /**
139 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 查看文件

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

+ 120
- 89
modules/UI/side_pannels/chat/Chat.js 查看文件

@@ -1,8 +1,8 @@
1 1
 /* global APP, $ */
2 2
 
3
-import {processReplacements, linkify} from './Replacement';
3
+import { processReplacements, linkify } from './Replacement';
4 4
 import CommandsProcessor from './Commands';
5
-import VideoLayout from "../../videolayout/VideoLayout";
5
+import VideoLayout from '../../videolayout/VideoLayout';
6 6
 
7 7
 import UIUtil from '../../util/UIUtil';
8 8
 import UIEvents from '../../../../service/UI/UIEvents';
@@ -36,6 +36,9 @@ const htmlStr = `
36 36
         </div>
37 37
     </div>`;
38 38
 
39
+/**
40
+ *
41
+ */
39 42
 function initHTML() {
40 43
     $(`#${sidePanelsContainerId}`)
41 44
         .append(htmlStr);
@@ -44,7 +47,7 @@ function initHTML() {
44 47
 /**
45 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 53
  *  Updates visual notification, indicating that a message has arrived.
@@ -66,19 +69,15 @@ function updateVisualNotification() {
66 69
             = document.getElementById('toolbar_button_chat');
67 70
         const leftIndent
68 71
             = (UIUtil.getTextWidth(chatButtonElement)
69
-                    - UIUtil.getTextWidth(unreadMsgElement))
70
-                / 2;
72
+                - UIUtil.getTextWidth(unreadMsgElement)) / 2;
71 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 77
         unreadMsgElement.setAttribute(
78 78
                 'style',
79
-                'top:' + topIndent + '; left:' + leftIndent + ';');
80
-    }
81
-    else {
79
+                `top:${topIndent}; left:${leftIndent};`);
80
+    } else {
82 81
         unreadMsgSelector.html('');
83 82
     }
84 83
 
@@ -93,37 +92,49 @@ function updateVisualNotification() {
93 92
  * @returns {string}
94 93
  */
95 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 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 122
     } else {
117
-        smileys.hide("slide", { direction: "down", duration: 300});
123
+        smileys.show('slide', { direction: 'down',
124
+            duration: 300 });
118 125
     }
119 126
     $('#usermsg').focus();
120 127
 }
121 128
 
129
+/**
130
+ *
131
+ */
122 132
 function addClickFunction(smiley, number) {
123 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 138
         usermsg.val(message);
128 139
         usermsg.get(0).setSelectionRange(message.length, message.length);
129 140
         toggleSmileys();
@@ -135,35 +146,38 @@ function addClickFunction(smiley, number) {
135 146
  * Adds the smileys container to the chat
136 147
  */
137 148
 function addSmileys() {
138
-    var smileysContainer = document.createElement('div');
149
+    const smileysContainer = document.createElement('div');
150
+
139 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 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 161
         addClickFunction(smiley, i);
148 162
         smileyContainer.appendChild(smiley);
149 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 170
  * Resizes the chat conversation.
157 171
  */
158 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 179
     smileys.height(msgareaHeight);
166
-    $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
180
+    $('#smileys').css('bottom', (msgareaHeight - 26) / 2);
167 181
     $('#smileysContainer').css('bottom', msgareaHeight);
168 182
     chat.width(width - 10);
169 183
     chat.height(window.innerHeight - 15 - msgareaHeight);
@@ -175,63 +189,71 @@ function resizeChatConversation() {
175 189
  *
176 190
  * @param id {string} input id
177 191
  */
178
-function deferredFocus(id){
192
+function deferredFocus(id) {
179 193
     setTimeout(() => $(`#${id}`).focus(), 400);
180 194
 }
195
+
181 196
 /**
182 197
  * Chat related user interface.
183 198
  */
184
-var Chat = {
199
+const Chat = {
185 200
     /**
186 201
      * Initializes chat related interface.
187 202
      */
188
-    init (eventEmitter) {
203
+    init(eventEmitter) {
189 204
         initHTML();
190 205
         if (APP.conference.getLocalDisplayName()) {
191 206
             Chat.setChatConversationMode(true);
192 207
         }
193 208
 
194
-        $("#smileys").click(function() {
209
+        $('#smileys').click(() => {
195 210
             Chat.toggleSmileys();
196 211
         });
197 212
 
198
-        $('#nickinput').keydown(function (event) {
213
+        $('#nickinput').keydown(function(event) {
199 214
             if (event.keyCode === 13) {
200 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 219
                 eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
204 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 227
             if (event.keyCode === 13) {
211 228
                 event.preventDefault();
212
-                var value = this.value;
229
+                const value = this.value; // eslint-disable-line no-invalid-this
230
+
213 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 235
                 if (command.isCommand()) {
217 236
                     command.processCommand();
218 237
                 } else {
219
-                    var message = UIUtil.escapeHtml(value);
238
+                    const message = UIUtil.escapeHtml(value);
239
+
220 240
                     eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
221 241
                 }
222 242
             }
223 243
         });
224 244
 
225
-        var onTextAreaResize = function () {
245
+        const onTextAreaResize = function() {
226 246
             resizeChatConversation();
227 247
             Chat.scrollChatToBottom();
228 248
         };
229
-        usermsg.autosize({callback: onTextAreaResize});
249
+
250
+        usermsg.autosize({ callback: onTextAreaResize });
230 251
 
231 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 255
                     return;
256
+                }
235 257
 
236 258
                 unreadMessages = 0;
237 259
                 updateVisualNotification();
@@ -257,13 +279,14 @@ var Chat = {
257 279
     /**
258 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 286
         if (APP.conference.isLocalId(id)) {
264
-            divClassName = "localuser";
287
+            divClassName = 'localuser';
265 288
         } else {
266
-            divClassName = "remoteuser";
289
+            divClassName = 'remoteuser';
267 290
 
268 291
             if (!Chat.isVisible()) {
269 292
                 unreadMessages++;
@@ -275,22 +298,25 @@ var Chat = {
275 298
         // replace links and smileys
276 299
         // Strophe already escapes special symbols on sending,
277 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 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 317
         $('#chatconversation').append(messageContainer);
292 318
         $('#chatconversation').animate(
293
-                { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
319
+                { scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
294 320
     },
295 321
 
296 322
     /**
@@ -298,25 +324,28 @@ var Chat = {
298 324
      * @param errorMessage the received error message.
299 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 329
         errorMessage = UIUtil.escapeHtml(errorMessage);
330
+        // eslint-disable-next-line no-param-reassign
303 331
         originalText = UIUtil.escapeHtml(originalText);
304 332
 
305 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 338
         $('#chatconversation').animate(
311
-            { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
339
+            { scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
312 340
     },
313 341
 
314 342
     /**
315 343
      * Sets the subject to the UI
316 344
      * @param subject the subject
317 345
      */
318
-    setSubject (subject) {
346
+    setSubject(subject) {
319 347
         if (subject) {
348
+            // eslint-disable-next-line no-param-reassign
320 349
             subject = subject.trim();
321 350
         }
322 351
 
@@ -332,16 +361,17 @@ var Chat = {
332 361
      * @param {boolean} isConversationMode if chat should be in
333 362
      * conversation mode or not.
334 363
      */
335
-    setChatConversationMode (isConversationMode) {
336
-        $('#' + CHAT_CONTAINER_ID)
364
+    setChatConversationMode(isConversationMode) {
365
+        $(`#${CHAT_CONTAINER_ID}`)
337 366
             .toggleClass('is-conversation-mode', isConversationMode);
338 367
     },
339 368
 
340 369
     /**
341 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 376
         resizeChatConversation();
347 377
     },
@@ -349,10 +379,11 @@ var Chat = {
349 379
     /**
350 380
      * Indicates if the chat is currently visible.
351 381
      */
352
-    isVisible () {
382
+    isVisible() {
353 383
         return UIUtil.isVisible(
354 384
             document.getElementById(CHAT_CONTAINER_ID));
355 385
     },
386
+
356 387
     /**
357 388
      * Shows and hides the window with the smileys
358 389
      */
@@ -361,7 +392,7 @@ var Chat = {
361 392
     /**
362 393
      * Scrolls chat to the bottom.
363 394
      */
364
-    scrollChatToBottom () {
395
+    scrollChatToBottom() {
365 396
         setTimeout(
366 397
             () => {
367 398
                 const chatconversation = $('#chatconversation');

+ 16
- 10
modules/UI/side_pannels/chat/Commands.js 查看文件

@@ -7,7 +7,7 @@ import UIEvents from '../../../../service/UI/UIEvents';
7 7
  * @type {{String: function}}
8 8
  */
9 9
 const commands = {
10
-    "topic" : processTopic
10
+    'topic': processTopic
11 11
 };
12 12
 
13 13
 /**
@@ -16,13 +16,15 @@ const commands = {
16 16
  * @returns {string} the command
17 17
  */
18 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 22
                 return command;
23
+            }
23 24
         }
24 25
     }
25
-    return "";
26
+
27
+    return '';
26 28
 }
27 29
 
28 30
 /**
@@ -30,7 +32,8 @@ function getCommand(message) {
30 32
  * @param commandArguments the arguments of the topic command.
31 33
  */
32 34
 function processTopic(commandArguments, emitter) {
33
-    var topic = UIUtil.escapeHtml(commandArguments);
35
+    const topic = UIUtil.escapeHtml(commandArguments);
36
+
34 37
     emitter.emit(UIEvents.SUBJECT_CHANGED, topic);
35 38
 }
36 39
 
@@ -41,7 +44,7 @@ function processTopic(commandArguments, emitter) {
41 44
  * @constructor
42 45
  */
43 46
 function CommandsProcessor(message, emitter) {
44
-    var command = getCommand(message);
47
+    const command = getCommand(message);
45 48
 
46 49
     this.emitter = emitter;
47 50
 
@@ -54,7 +57,7 @@ function CommandsProcessor(message, emitter) {
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 63
      * Returns the arguments of the command.
@@ -70,8 +73,10 @@ function CommandsProcessor(message, emitter) {
70 73
  * @returns {boolean}
71 74
  */
72 75
 CommandsProcessor.prototype.isCommand = function() {
73
-    if (this.getCommand())
76
+    if (this.getCommand()) {
74 77
         return true;
78
+    }
79
+
75 80
     return false;
76 81
 };
77 82
 
@@ -79,8 +84,9 @@ CommandsProcessor.prototype.isCommand = function() {
79 84
  * Processes the command.
80 85
  */
81 86
 CommandsProcessor.prototype.processCommand = function() {
82
-    if(!this.isCommand())
87
+    if (!this.isCommand()) {
83 88
         return;
89
+    }
84 90
 
85 91
     commands[this.getCommand()](this.getArgument(), this.emitter);
86 92
 };

+ 20
- 21
modules/UI/side_pannels/chat/Replacement.js 查看文件

@@ -1,17 +1,11 @@
1
-/* jshint -W101 */
2 1
 import { regexes } from './smileys';
3 2
 
4 3
 /**
5 4
  * Processes links and smileys in "body"
6 5
  */
7 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,20 +13,23 @@ export function processReplacements(body) {
19 13
  * with their <a href=""></a>
20 14
  */
21 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 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 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 33
     replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
37 34
 
38 35
     /* eslint-enable no-useless-escape */
@@ -44,14 +41,16 @@ export function linkify(inputText) {
44 41
  * Replaces common smiley strings with images
45 42
  */
46 43
 function smilify(body) {
47
-    if(!body) {
44
+    if (!body) {
48 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 查看文件

@@ -1,25 +1,25 @@
1 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 25
 export const regexes = {

+ 3
- 5
modules/UI/side_pannels/contactlist/ContactListView.js 查看文件

@@ -19,7 +19,7 @@ import UIUtil from '../../util/UIUtil';
19 19
  * the term "contact" is not used elsewhere. Normally people in the conference
20 20
  * are internally refered to as "participants" or externally as "members".
21 21
  */
22
-var ContactListView = {
22
+const ContactListView = {
23 23
     /**
24 24
      * Creates and appends the contact list to the side panel.
25 25
      *
@@ -33,7 +33,6 @@ var ContactListView = {
33 33
 
34 34
         $('#sideToolbarContainer').append(contactListPanelContainer);
35 35
 
36
-        /* jshint ignore:start */
37 36
         ReactDOM.render(
38 37
             <Provider store = { APP.store }>
39 38
                 <I18nextProvider i18n = { i18next }>
@@ -42,7 +41,6 @@ var ContactListView = {
42 41
             </Provider>,
43 42
             contactListPanelContainer
44 43
         );
45
-        /* jshint ignore:end */
46 44
     },
47 45
 
48 46
     /**
@@ -50,8 +48,8 @@ var ContactListView = {
50 48
      *
51 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 查看文件

@@ -1,98 +1,117 @@
1 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 4
 import Settings from '../../../settings/Settings';
5 5
 
6 6
 import { sendEvent } from '../../../../react/features/analytics';
7 7
 
8 8
 const sidePanelsContainerId = 'sideToolbarContainer';
9 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 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 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 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 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 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 33
                 </li>
34 34
             </ul>
35 35
         </div>
36 36
     </div>`;
37 37
 
38
+/**
39
+ *
40
+ */
38 41
 function initHTML() {
39 42
     $(`#${sidePanelsContainerId}`)
40 43
         .append(htmlStr);
44
+
41 45
     // make sure we translate the panel, as adding it can be after i18n
42 46
     // library had initialized and translated already present html
43 47
     APP.translation.translateElement($(`#${sidePanelsContainerId}`));
44 48
 }
45 49
 
46 50
 export default {
47
-    init (emitter) {
51
+    init(emitter) {
48 52
         initHTML();
49
-        // DISPLAY NAME
50
-        function updateDisplayName () {
53
+
54
+        /**
55
+         * Updates display name.
56
+         *
57
+         * @returns {void}
58
+         */
59
+        function updateDisplayName() {
51 60
             emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
52 61
         }
53 62
 
54 63
         $('#setDisplayName')
55 64
             .val(Settings.getDisplayName())
56
-            .keyup(function (event) {
65
+            .keyup(event => {
57 66
                 if (event.keyCode === 13) { // enter
58 67
                     updateDisplayName();
59 68
                 }
60 69
             })
61 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 78
             emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
67 79
         }
68 80
 
69 81
         $('#setEmail')
70 82
             .val(Settings.getEmail())
71
-            .keyup(function (event) {
83
+            .keyup(event => {
72 84
                 if (event.keyCode === 13) { // enter
73 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 94
             sendEvent('authenticate.login.clicked');
80 95
             emitter.emit(UIEvents.AUTH_CLICKED);
81 96
         }
82 97
 
83 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 107
             sendEvent('authenticate.logout.clicked');
108
+
90 109
             // Ask for confirmation
91 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 115
                     if (yes) {
97 116
                         emitter.emit(UIEvents.LOGOUT);
98 117
                     }
@@ -107,15 +126,15 @@ export default {
107 126
      * Check if settings menu is visible or not.
108 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 134
      * Change user display name in the settings menu.
116 135
      * @param {string} newDisplayName
117 136
      */
118
-    changeDisplayName (newDisplayName) {
137
+    changeDisplayName(newDisplayName) {
119 138
         $('#setDisplayName').val(newDisplayName);
120 139
     },
121 140
 
@@ -123,7 +142,7 @@ export default {
123 142
      * Change user avatar in the settings menu.
124 143
      * @param {string} avatarUrl url of the new avatar
125 144
      */
126
-    changeAvatar (avatarUrl) {
145
+    changeAvatar(avatarUrl) {
127 146
         $('#avatar').attr('src', avatarUrl);
128 147
     },
129 148
 
@@ -131,7 +150,7 @@ export default {
131 150
      * Change the value of the field for the user email.
132 151
      * @param {string} email the new value that will be displayed in the field.
133 152
      */
134
-    changeEmail (email) {
153
+    changeEmail(email) {
135 154
         $('#setEmail').val(email);
136 155
     },
137 156
 
@@ -139,8 +158,9 @@ export default {
139 158
      * Shows or hides authentication related buttons
140 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 164
         UIUtil.setVisible(id, show);
145 165
     },
146 166
 
@@ -148,8 +168,8 @@ export default {
148 168
      * Shows/hides login button.
149 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 174
         UIUtil.setVisible(id, show);
155 175
     },
@@ -158,8 +178,8 @@ export default {
158 178
      * Shows/hides logout button.
159 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 184
         UIUtil.setVisible(id, show);
165 185
     },
@@ -168,10 +188,10 @@ export default {
168 188
      * Displays user's authenticated identity name (login).
169 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 196
         $(`#${id}`).text(authIdentity ? authIdentity : '');
177 197
     }

+ 58
- 40
modules/UI/side_pannels/settings/SettingsMenu.js 查看文件

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

@@ -1,5 +1,5 @@
1 1
 /* global $, APP */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
2
+const logger = require('jitsi-meet-logger').getLogger(__filename);
3 3
 
4 4
 import jitsiLocalStorage from '../../util/JitsiLocalStorage';
5 5
 
@@ -31,12 +31,14 @@ let twoButtonDialog = null;
31 31
  * @returns {string}
32 32
  */
33 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 42
     return `<br />
41 43
         <label>
42 44
             <input type='checkbox' ${checked} id='${options.id}' />
@@ -54,12 +56,13 @@ function generateDontShowCheckbox(options) {
54 56
  * false otherwise.
55 57
  */
56 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 62
             return true;
61 63
         }
62 64
     }
65
+
63 66
     return false;
64 67
 }
65 68
 
@@ -76,24 +79,27 @@ function dontShowTheDialog(options) {
76 79
  * @returns {Function} wrapped function
77 80
  */
78 81
 function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
79
-    if(isDontShowAgainEnabled(options)) {
82
+    if (isDontShowAgainEnabled(options)) {
80 83
         return (...args) => {
81 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 91
                 if (checkbox.length) {
87 92
                     jitsiLocalStorage.setItem(
88 93
                         options.localStorageKey || options.id,
89
-                        checkbox.prop("checked"));
94
+                        checkbox.prop('checked'));
90 95
                 }
91 96
             }
92 97
             submitFunction(...args);
93 98
         };
94
-    } else {
95
-        return submitFunction;
96 99
     }
100
+
101
+    return submitFunction;
102
+
97 103
 }
98 104
 
99 105
 /**
@@ -102,12 +108,12 @@ function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
102 108
  * @returns {boolean} true if enabled and false if not.
103 109
  */
104 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 119
      * Shows a message to the user.
@@ -120,25 +126,32 @@ var messageHandler = {
120 126
      * the prompt is closed (optional)
121 127
      * @return the prompt that was created, or null
122 128
      */
129
+    // eslint-disable-next-line max-params
123 130
     openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
124
-        if (!popupEnabled)
131
+        if (!popupEnabled) {
125 132
             return null;
133
+        }
126 134
 
127
-        let dialog = $.prompt(
135
+        const dialog = $.prompt(
128 136
             APP.translation.generateTranslationHTML(messageKey, i18nOptions),
129 137
             {
130 138
                 title: this._getFormattedTitleString(titleKey),
131 139
                 persistent: false,
132 140
                 promptspeed: 0,
133 141
                 classes: this._getDialogClasses(),
142
+                // eslint-disable-next-line max-params
134 143
                 close(e, v, m, f) {
135
-                    if(closeFunction)
144
+                    if (closeFunction) {
136 145
                         closeFunction(e, v, m, f);
146
+                    }
137 147
                 }
138 148
             });
149
+
139 150
         APP.translation.translateElement(dialog, i18nOptions);
151
+
140 152
         return $.prompt.getApi();
141 153
     },
154
+
142 155
     /**
143 156
      * Shows a message to the user with two buttons: first is given as a
144 157
      * parameter and the second is Cancel.
@@ -169,8 +182,8 @@ var messageHandler = {
169 182
      * storage. if not provided dontShowAgain.id will be used.
170 183
      * @return the prompt that was created, or null
171 184
      */
172
-    openTwoButtonDialog: function(options) {
173
-        let {
185
+    openTwoButtonDialog(options) {
186
+        const {
174 187
             titleKey,
175 188
             msgKey,
176 189
             msgString,
@@ -182,32 +195,40 @@ var messageHandler = {
182 195
             size,
183 196
             defaultButton,
184 197
             wrapperClass,
185
-            classes,
186 198
             dontShowAgain
187 199
         } = options;
188 200
 
189
-        if (!popupEnabled || twoButtonDialog)
201
+        let { classes } = options;
202
+
203
+        if (!popupEnabled || twoButtonDialog) {
190 204
             return null;
205
+        }
191 206
 
192
-        if(dontShowTheDialog(dontShowAgain)) {
207
+        if (dontShowTheDialog(dontShowAgain)) {
193 208
             // Maybe we should pass some parameters here? I'm not sure
194 209
             // and currently we don't need any parameters.
195 210
             submitFunction();
211
+
196 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 232
         if (msgKey) {
212 233
             message = APP.translation.generateTranslationHTML(msgKey);
213 234
         }
@@ -220,20 +241,20 @@ var messageHandler = {
220 241
         twoButtonDialog = $.prompt(message, {
221 242
             title: this._getFormattedTitleString(titleKey),
222 243
             persistent: false,
223
-            buttons: buttons,
224
-            defaultButton: defaultButton,
225
-            focus: focus,
244
+            buttons,
245
+            defaultButton,
246
+            focus,
226 247
             loaded: loadedFunction,
227 248
             promptspeed: 0,
228 249
             classes,
229 250
             submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
230
-                function (e, v, m, f) {
251
+                (e, v, m, f) => { // eslint-disable-line max-params
231 252
                     twoButtonDialog = null;
232 253
                     if (v && submitFunction) {
233 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 258
                 twoButtonDialog = null;
238 259
                 if (closeFunction) {
239 260
                     closeFunction(e, v, m, f);
@@ -241,6 +262,7 @@ var messageHandler = {
241 262
             }
242 263
         });
243 264
         APP.translation.translateElement(twoButtonDialog);
265
+
244 266
         return $.prompt.getApi();
245 267
     },
246 268
 
@@ -270,7 +292,7 @@ var messageHandler = {
270 292
      * @param {string} dontShowAgain.localStorageKey the key for the local
271 293
      * storage. if not provided dontShowAgain.id will be used.
272 294
      */
273
-    openDialog(
295
+    openDialog(// eslint-disable-line max-params
274 296
             titleKey,
275 297
             msgString,
276 298
             persistent,
@@ -279,29 +301,33 @@ var messageHandler = {
279 301
             loadedFunction,
280 302
             closeFunction,
281 303
             dontShowAgain) {
282
-        if (!popupEnabled)
304
+        if (!popupEnabled) {
283 305
             return;
306
+        }
284 307
 
285
-        if(dontShowTheDialog(dontShowAgain)) {
308
+        if (dontShowTheDialog(dontShowAgain)) {
286 309
             // Maybe we should pass some parameters here? I'm not sure
287 310
             // and currently we don't need any parameters.
288 311
             submitFunction();
312
+
289 313
             return;
290 314
         }
291 315
 
292
-        let args = {
316
+        const args = {
293 317
             title: this._getFormattedTitleString(titleKey),
294
-            persistent: persistent,
295
-            buttons: buttons,
318
+            persistent,
319
+            buttons,
296 320
             defaultButton: 1,
297 321
             promptspeed: 0,
298
-            loaded: function() {
322
+            loaded() {
299 323
                 if (loadedFunction) {
324
+                    // eslint-disable-next-line prefer-rest-params
300 325
                     loadedFunction.apply(this, arguments);
301 326
                 }
327
+
302 328
                 // Hide the close button
303 329
                 if (persistent) {
304
-                    $(".jqiclose", this).hide();
330
+                    $('.jqiclose', this).hide();
305 331
                 }
306 332
             },
307 333
             submit: dontShowAgainSubmitFunctionWrapper(
@@ -314,9 +340,11 @@ var messageHandler = {
314 340
             args.closeText = '';
315 341
         }
316 342
 
317
-        let dialog = $.prompt(
343
+        const dialog = $.prompt(
318 344
             msgString + generateDontShowCheckbox(dontShowAgain), args);
345
+
319 346
         APP.translation.translateElement(dialog);
347
+
320 348
         return $.prompt.getApi();
321 349
     },
322 350
 
@@ -326,10 +354,13 @@ var messageHandler = {
326 354
      * @return the title string formatted as a div.
327 355
      */
328 356
     _getFormattedTitleString(titleKey) {
329
-        let $titleString = $('<h2>');
357
+        const $titleString = $('<h2>');
358
+
330 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,23 +390,28 @@ var messageHandler = {
359 390
      * @param options impromptu options
360 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 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 400
         options.classes = Object.assign({}, defaultClasses, classes);
368 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 407
                 currentState.title
374 408
                     = this._getFormattedTitleString(currentState.titleKey);
375 409
             }
376 410
         }
377
-        let dialog = $.prompt(statesObject, options);
411
+        const dialog = $.prompt(statesObject, options);
412
+
378 413
         APP.translation.translateElement(dialog, translateOptions);
414
+
379 415
         return $.prompt.getApi();
380 416
     },
381 417
 
@@ -392,17 +428,20 @@ var messageHandler = {
392 428
      * @returns {object} popup window object if opened successfully or undefined
393 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 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 440
             url, '_blank',
403
-            'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
441
+            String(`top=${t}, left=${l}, width=${w}, height=${h}`));
442
+
404 443
         if (popup && onPopupClosed) {
405
-            var pollTimer = window.setInterval(function () {
444
+            const pollTimer = window.setInterval(() => {
406 445
                 if (popup.closed !== false) {
407 446
                     window.clearInterval(pollTimer);
408 447
                     onPopupClosed();
@@ -420,10 +459,11 @@ var messageHandler = {
420 459
      * @param msgKey the text of the message
421 460
      * @param error the error that is being reported
422 461
      */
423
-    openReportDialog: function(titleKey, msgKey, error) {
462
+    openReportDialog(titleKey, msgKey, error) {
424 463
         this.openMessageDialog(titleKey, msgKey);
425 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,14 +471,7 @@ var messageHandler = {
431 471
      * @param titleKey the title of the message.
432 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 475
         messageHandler.openMessageDialog(titleKey, msgKey);
443 476
     },
444 477
 
@@ -454,7 +487,7 @@ var messageHandler = {
454 487
      * @param messageArguments object with the arguments for the message.
455 488
      * @param optional configurations for the notification (e.g. timeout)
456 489
      */
457
-    participantNotification(
490
+    participantNotification( // eslint-disable-line max-params
458 491
             displayName,
459 492
             displayNameKey,
460 493
             cls,
@@ -484,12 +517,12 @@ var messageHandler = {
484 517
      * translation.
485 518
      * @returns {void}
486 519
      */
487
-    notify: function(titleKey, messageKey, messageArguments) {
520
+    notify(titleKey, messageKey, messageArguments) {
488 521
         this.participantNotification(
489 522
             null, titleKey, null, messageKey, messageArguments);
490 523
     },
491 524
 
492
-    enablePopups: function (enable) {
525
+    enablePopups(enable) {
493 526
         popupEnabled = enable;
494 527
     },
495 528
 
@@ -498,8 +531,8 @@ var messageHandler = {
498 531
      * false otherwise
499 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 查看文件

@@ -31,7 +31,7 @@ const IndicatorFontSizes = {
31 31
 /**
32 32
  * Created by hristo on 12/22/14.
33 33
  */
34
-var UIUtil = {
34
+const UIUtil = {
35 35
 
36 36
     /**
37 37
      * Returns the available video width.
@@ -43,17 +43,18 @@ var UIUtil = {
43 43
     /**
44 44
      * Changes the style class of the element given by id.
45 45
      */
46
-    buttonClick: function(id, classname) {
46
+    buttonClick(id, classname) {
47 47
         // add the class to the clicked element
48
-        $("#" + id).toggleClass(classname);
48
+        $(`#${id}`).toggleClass(classname);
49 49
     },
50
+
50 51
     /**
51 52
      * Returns the text width for the given element.
52 53
      *
53 54
      * @param el the element
54 55
      */
55 56
     getTextWidth(el) {
56
-        return (el.clientWidth + 1);
57
+        return el.clientWidth + 1;
57 58
     },
58 59
 
59 60
     /**
@@ -62,7 +63,7 @@ var UIUtil = {
62 63
      * @param el the element
63 64
      */
64 65
     getTextHeight(el) {
65
-        return (el.clientHeight + 1);
66
+        return el.clientHeight + 1;
66 67
     },
67 68
 
68 69
     /**
@@ -78,7 +79,8 @@ var UIUtil = {
78 79
      * Escapes the given text.
79 80
      */
80 81
     escapeHtml(unsafeText) {
81
-        return $('<div/>').text(unsafeText).html();
82
+        return $('<div/>').text(unsafeText)
83
+            .html();
82 84
     },
83 85
 
84 86
     /**
@@ -88,22 +90,27 @@ var UIUtil = {
88 90
      * @returns {string} unescaped html string.
89 91
      */
90 92
     unescapeHtml(safe) {
91
-        return $('<div />').html(safe).text();
93
+        return $('<div />').html(safe)
94
+            .text();
92 95
     },
93 96
 
94 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 111
             // pixels[i+3]              is alpha
106 112
         }
113
+
107 114
         // redraw the image in black & white
108 115
         context.putImageData(imgData, 0, 0);
109 116
     },
@@ -114,7 +121,8 @@ var UIUtil = {
114 121
      * @param newChild the new element that will be inserted into the container
115 122
      */
116 123
     prependChild(container, newChild) {
117
-        var firstChild = container.childNodes[0];
124
+        const firstChild = container.childNodes[0];
125
+
118 126
         if (firstChild) {
119 127
             container.insertBefore(newChild, firstChild);
120 128
         } else {
@@ -152,6 +160,7 @@ var UIUtil = {
152 160
      */
153 161
     setVisible(id, visible) {
154 162
         let element;
163
+
155 164
         if (id instanceof HTMLElement) {
156 165
             element = id;
157 166
         } else {
@@ -162,20 +171,20 @@ var UIUtil = {
162 171
             return;
163 172
         }
164 173
 
165
-        if (!visible)
174
+        if (!visible) {
166 175
             element.classList.add('hide');
167
-        else if (element.classList.contains('hide')) {
176
+        } else if (element.classList.contains('hide')) {
168 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 183
         if (visible) {
175 184
             element.classList.add(className);
176
-        }
177
-        else if (element.classList.contains(className))
185
+        } else if (element.classList.contains(className)) {
178 186
             element.classList.remove(className);
187
+        }
179 188
     },
180 189
 
181 190
     /**
@@ -185,10 +194,11 @@ var UIUtil = {
185 194
      * @private
186 195
      */
187 196
     _getElementDefaultDisplay(tag) {
188
-        let tempElement = document.createElement(tag);
197
+        const tempElement = document.createElement(tag);
189 198
 
190 199
         document.body.appendChild(tempElement);
191
-        let style = window.getComputedStyle(tempElement).display;
200
+        const style = window.getComputedStyle(tempElement).display;
201
+
192 202
         document.body.removeChild(tempElement);
193 203
 
194 204
         return style;
@@ -203,7 +213,7 @@ var UIUtil = {
203 213
      */
204 214
     setVisibleBySelector(jquerySelector, isVisible) {
205 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,7 +274,8 @@ var UIUtil = {
264 274
       */
265 275
     attrsToString(attrs) {
266 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,7 +286,7 @@ var UIUtil = {
275 286
      * @param {el} The DOM element we'd like to check for visibility
276 287
      */
277 288
     isVisible(el) {
278
-        return (el.offsetParent !== null);
289
+        return el.offsetParent !== null;
279 290
     },
280 291
 
281 292
     /**
@@ -288,26 +299,33 @@ var UIUtil = {
288 299
      * element
289 300
      */
290 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 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 314
                 setTimeout(
301 315
                     () => {
302 316
                         selector.fadeOut(
303 317
                             300,
304
-                            () => { selector.css({opacity: 0}); });
318
+                            () => {
319
+                                selector.css({ opacity: 0 });
320
+                            });
305 321
                     },
306 322
                     hideDelay);
307
-        }
308
-        else {
323
+            }
324
+        } else {
309 325
             selector.fadeOut(300,
310
-                () => {selector.css({opacity: 0});}
326
+                () => {
327
+                    selector.css({ opacity: 0 });
328
+                }
311 329
             );
312 330
         }
313 331
     },
@@ -318,7 +336,7 @@ var UIUtil = {
318 336
      * @param cssValue the string value we obtain when querying css properties
319 337
      */
320 338
     parseCssInt(cssValue) {
321
-        return parseInt(cssValue) || 0;
339
+        return parseInt(cssValue, 10) || 0;
322 340
     },
323 341
 
324 342
     /**
@@ -332,8 +350,8 @@ var UIUtil = {
332 350
             aLinkElement.attr('href', link);
333 351
         } else {
334 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 查看文件

@@ -2,8 +2,8 @@
2 2
 
3 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 8
 import { sendEvent } from '../../../react/features/analytics';
9 9
 
@@ -13,7 +13,7 @@ const Filmstrip = {
13 13
      * @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
14 14
      * emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
15 15
      */
16
-    init (eventEmitter) {
16
+    init(eventEmitter) {
17 17
         this.iconMenuDownClassName = 'icon-menu-down';
18 18
         this.iconMenuUpClassName = 'icon-menu-up';
19 19
         this.filmstripContainerClassName = 'filmstrip';
@@ -33,13 +33,14 @@ const Filmstrip = {
33 33
      * Initializes the filmstrip toolbar.
34 34
      */
35 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 40
         UIUtil.prependChild(container, toolbarContainerHTML);
41 41
 
42
-        let iconSelector = '#toggleFilmstripButton i';
42
+        const iconSelector = '#toggleFilmstripButton i';
43
+
43 44
         this.toggleFilmstripIcon = document.querySelector(iconSelector);
44 45
     },
45 46
 
@@ -49,8 +50,9 @@ const Filmstrip = {
49 50
      * @private
50 51
      */
51 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 56
         container.className = 'filmstrip__toolbar';
55 57
         container.innerHTML = `
56 58
             <button id="toggleFilmstripButton">
@@ -81,14 +83,15 @@ const Filmstrip = {
81 83
      * @private
82 84
      */
83 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 90
         // Important:
88 91
         // Firing the event instead of executing toggleFilmstrip method because
89 92
         // it's important to hide the filmstrip by UI.toggleFilmstrip in order
90 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 96
         APP.keyboardshortcut.registerShortcut(
94 97
             shortcut,
@@ -102,8 +105,9 @@ const Filmstrip = {
102 105
      * Changes classes of icon for showing down state
103 106
      */
104 107
     showMenuDownIcon() {
105
-        let icon = this.toggleFilmstripIcon;
106
-        if(icon) {
108
+        const icon = this.toggleFilmstripIcon;
109
+
110
+        if (icon) {
107 111
             icon.classList.add(this.iconMenuDownClassName);
108 112
             icon.classList.remove(this.iconMenuUpClassName);
109 113
         }
@@ -113,8 +117,9 @@ const Filmstrip = {
113 117
      * Changes classes of icon for showing up state
114 118
      */
115 119
     showMenuUpIcon() {
116
-        let icon = this.toggleFilmstripIcon;
117
-        if(icon) {
120
+        const icon = this.toggleFilmstripIcon;
121
+
122
+        if (icon) {
118 123
             icon.classList.add(this.iconMenuUpClassName);
119 124
             icon.classList.remove(this.iconMenuDownClassName);
120 125
         }
@@ -137,7 +142,9 @@ const Filmstrip = {
137 142
      */
138 143
     toggleFilmstrip(visible, sendAnalytics = true) {
139 144
         const isVisibleDefined = typeof visible === 'boolean';
145
+
140 146
         if (!isVisibleDefined) {
147
+            // eslint-disable-next-line no-param-reassign
141 148
             visible = this.isFilmstripVisible();
142 149
         } else if (this.isFilmstripVisible() === visible) {
143 150
             return;
@@ -145,7 +152,7 @@ const Filmstrip = {
145 152
         if (sendAnalytics) {
146 153
             sendEvent('toolbar.filmstrip.toggled');
147 154
         }
148
-        this.filmstrip.toggleClass("hidden");
155
+        this.filmstrip.toggleClass('hidden');
149 156
 
150 157
         if (visible) {
151 158
             this.showMenuUpIcon();
@@ -190,9 +197,10 @@ const Filmstrip = {
190 197
         // display should be.
191 198
         if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
192 199
             return $(`.${this.filmstripContainerClassName}`).outerHeight();
193
-        } else {
194
-            return 0;
195 200
         }
201
+
202
+        return 0;
203
+
196 204
     },
197 205
 
198 206
     /**
@@ -200,9 +208,9 @@ const Filmstrip = {
200 208
      * @returns {*|{localVideo, remoteVideo}}
201 209
      */
202 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 215
         return this.calculateThumbnailSizeFromAvailable(width, height);
208 216
     },
@@ -215,17 +223,17 @@ const Filmstrip = {
215 223
      */
216 224
     calculateAvailableSize() {
217 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 232
          * If the videoAreaAvailableWidth is set we use this one to calculate
225 233
          * the filmstrip width, because we're probably in a state where the
226 234
          * filmstrip size hasn't been updated yet, but it will be.
227 235
          */
228
-        let videoAreaAvailableWidth
236
+        const videoAreaAvailableWidth
229 237
             = UIUtil.getAvailableVideoWidth()
230 238
             - this._getFilmstripExtraPanelsWidth()
231 239
             - UIUtil.parseCssInt(this.filmstrip.css('right'), 10)
@@ -238,9 +246,9 @@ const Filmstrip = {
238 246
         let availableWidth = videoAreaAvailableWidth;
239 247
 
240 248
         // If local thumb is not hidden
241
-        if(thumbs.localThumb) {
249
+        if (thumbs.localThumb) {
242 250
             availableWidth = Math.floor(
243
-                (videoAreaAvailableWidth - (
251
+                videoAreaAvailableWidth - (
244 252
                     UIUtil.parseCssInt(
245 253
                         localVideoContainer.css('borderLeftWidth'), 10)
246 254
                     + UIUtil.parseCssInt(
@@ -252,7 +260,7 @@ const Filmstrip = {
252 260
                     + UIUtil.parseCssInt(
253 261
                         localVideoContainer.css('marginLeft'), 10)
254 262
                     + UIUtil.parseCssInt(
255
-                        localVideoContainer.css('marginRight'), 10)))
263
+                        localVideoContainer.css('marginRight'), 10))
256 264
             );
257 265
         }
258 266
 
@@ -260,9 +268,10 @@ const Filmstrip = {
260 268
         // filmstrip mode we don't need to calculate further any adjustments
261 269
         // to width based on the number of videos present.
262 270
         if (numvids && !interfaceConfig.VERTICAL_FILMSTRIP) {
263
-            let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
271
+            const remoteVideoContainer = thumbs.remoteThumbs.eq(0);
272
+
264 273
             availableWidth = Math.floor(
265
-                (videoAreaAvailableWidth - numvids * (
274
+                videoAreaAvailableWidth - (numvids * (
266 275
                     UIUtil.parseCssInt(
267 276
                         remoteVideoContainer.css('borderLeftWidth'), 10)
268 277
                     + UIUtil.parseCssInt(
@@ -278,7 +287,8 @@ const Filmstrip = {
278 287
             );
279 288
         }
280 289
 
281
-        let maxHeight
290
+        const maxHeight
291
+
282 292
             // If the MAX_HEIGHT property hasn't been specified
283 293
             // we have the static value.
284 294
             = Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
@@ -287,7 +297,8 @@ const Filmstrip = {
287 297
         availableHeight
288 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,15 +311,19 @@ const Filmstrip = {
300 311
      * @private
301 312
      */
302 313
     _getFilmstripExtraPanelsWidth() {
303
-        let className = this.filmstripContainerClassName;
314
+        const className = this.filmstripContainerClassName;
304 315
         let width = 0;
316
+
305 317
         $(`.${className}`)
306 318
             .children()
307
-            .each(function () {
319
+            .each(function() {
320
+                /* eslint-disable no-invalid-this */
308 321
                 if (this.id !== 'remoteVideos') {
309 322
                     width += $(this).outerWidth();
310 323
                 }
324
+                /* eslint-enable no-invalid-this */
311 325
             });
326
+
312 327
         return width;
313 328
     },
314 329
 
@@ -362,16 +377,17 @@ const Filmstrip = {
362 377
 
363 378
         const remoteThumbsInRow = interfaceConfig.VERTICAL_FILMSTRIP
364 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 385
         const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
371 386
 
372 387
         const remoteVideoWidth = lW * remoteLocalWidthRatio;
373 388
 
374 389
         let localVideo;
390
+
375 391
         if (interfaceConfig.VERTICAL_FILMSTRIP) {
376 392
             localVideo = {
377 393
                 thumbWidth: remoteVideoWidth,
@@ -401,28 +417,32 @@ const Filmstrip = {
401 417
      * @param forceUpdate
402 418
      * @returns {Promise}
403 419
      */
420
+    // eslint-disable-next-line max-params
404 421
     resizeThumbnails(local, remote, animate = false, forceUpdate = false) {
405 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 429
                     thumbs.localThumb.animate({
412 430
                         height: local.thumbHeight,
413 431
                         width: local.thumbWidth
414 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 438
                     thumbs.remoteThumbs.animate({
420 439
                         height: remote.thumbHeight,
421 440
                         width: remote.thumbWidth
422 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 446
                 // Let CSS take care of height in vertical filmstrip mode.
427 447
                 if (interfaceConfig.VERTICAL_FILMSTRIP) {
428 448
                     $('#filmstripLocalVideo').animate({
@@ -438,9 +458,10 @@ const Filmstrip = {
438 458
             }));
439 459
 
440 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 465
                 this.filmstrip.find('.indicator').animate({
445 466
                     fontSize
446 467
                 }, this._getAnimateOptions(animate, resolve));
@@ -471,24 +492,27 @@ const Filmstrip = {
471 492
 
472 493
     /**
473 494
      * Returns thumbnails of the filmstrip
474
-     * @param only_visible
495
+     * @param onlyVisible
475 496
      * @returns {object} thumbnails
476 497
      */
477
-    getThumbs(only_visible = false) {
498
+    getThumbs(onlyVisible = false) {
478 499
         let selector = 'span';
479
-        if (only_visible) {
500
+
501
+        if (onlyVisible) {
480 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 508
         // Exclude the local video container if it has been hidden.
487
-        if (localThumb.hasClass("hidden")) {
509
+        if (localThumb.hasClass('hidden')) {
488 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 查看文件

@@ -3,19 +3,19 @@
3 3
  * Base class for all Large containers which we can show.
4 4
  */
5 5
 export default class LargeContainer {
6
-
6
+    /* eslint-disable no-unused-vars, no-empty-function */
7 7
     /**
8 8
      * Show this container.
9 9
      * @returns Promise
10 10
      */
11
-    show () {
11
+    show() {
12 12
     }
13 13
 
14 14
     /**
15 15
      * Hide this container.
16 16
      * @returns Promise
17 17
      */
18
-    hide () {
18
+    hide() {
19 19
     }
20 20
 
21 21
     /**
@@ -24,20 +24,19 @@ export default class LargeContainer {
24 24
      * @param {number} containerHeight available height
25 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 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 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,14 +45,14 @@ export default class LargeContainer {
46 45
      * @param {JitsiTrack?} stream new stream
47 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 52
      * Show or hide user avatar.
54 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,6 +60,8 @@ export default class LargeContainer {
61 60
      * when the container is on stage.
62 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 查看文件

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

+ 48
- 38
modules/UI/videolayout/LocalVideo.js 查看文件

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

+ 97
- 74
modules/UI/videolayout/RemoteVideo.js 查看文件

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

+ 119
- 102
modules/UI/videolayout/SmallVideo.js 查看文件

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

+ 100
- 60
modules/UI/videolayout/VideoContainer.js 查看文件

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

+ 273
- 202
modules/UI/videolayout/VideoLayout.js
文件差異過大導致無法顯示
查看文件


+ 4
- 4
modules/URL/ConferenceUrl.js 查看文件

@@ -1,4 +1,4 @@
1
-const logger = require("jitsi-meet-logger").getLogger(__filename);
1
+const logger = require('jitsi-meet-logger').getLogger(__filename);
2 2
 
3 3
 /**
4 4
  * The modules stores information about the URL used to start the conference and
@@ -24,9 +24,9 @@ export default class ConferenceUrl {
24 24
      * from the sample URL.
25 25
      */
26 26
     constructor(location) {
27
-        logger.info("Stored original conference URL: " + location.href);
27
+        logger.info(`Stored original conference URL: ${location.href}`);
28 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 查看文件

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

+ 115
- 105
modules/keyboardshortcut/keyboardshortcut.js 查看文件

@@ -11,47 +11,6 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
11 11
  */
12 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 15
  * Shows or hides the keyboard shortcuts dialog.
57 16
  * @param {boolean} show whether to show or hide the dialog
@@ -60,8 +19,8 @@ function showKeyboardShortcutsPanel(show) {
60 19
     if (show
61 20
             && !APP.UI.messageHandler.isDialogOpened()
62 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 25
         keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
67 26
             'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
@@ -75,7 +34,7 @@ function showKeyboardShortcutsPanel(show) {
75 34
  * Map of shortcuts. When a shortcut is registered it enters the mapping.
76 35
  * @type {{}}
77 36
  */
78
-let _shortcuts = {};
37
+const _shortcuts = {};
79 38
 
80 39
 /**
81 40
  * True if the keyboard shortcuts are enabled and false if not.
@@ -87,43 +46,42 @@ let enabled = true;
87 46
  * Maps keycode to character, id of popover for given function and function.
88 47
  */
89 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 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 62
                 if (_shortcuts.hasOwnProperty(key)) {
104 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 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 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 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 85
                         logger.log('Talk shortcut released');
128 86
                         APP.conference.muteAudio(false);
129 87
                     }
@@ -136,7 +94,7 @@ const KeyboardShortcut = {
136 94
      * Enables/Disables the keyboard shortcuts.
137 95
      * @param {boolean} value - the new value.
138 96
      */
139
-    enable: function (value) {
97
+    enable(value) {
140 98
         enabled = value;
141 99
     },
142 100
 
@@ -151,19 +109,20 @@ const KeyboardShortcut = {
151 109
      * @param helpDescription the description of the shortcut that would appear
152 110
      * in the help menu
153 111
      */
154
-    registerShortcut(
112
+    registerShortcut(// eslint-disable-line max-params
155 113
             shortcutChar,
156 114
             shortcutAttr,
157 115
             exec,
158 116
             helpDescription) {
159 117
         _shortcuts[shortcutChar] = {
160 118
             character: shortcutChar,
161
-            shortcutAttr: shortcutAttr,
119
+            shortcutAttr,
162 120
             function: exec
163 121
         };
164 122
 
165
-        if (helpDescription)
123
+        if (helpDescription) {
166 124
             this._addShortcutToHelp(shortcutChar, helpDescription);
125
+        }
167 126
     },
168 127
 
169 128
     /**
@@ -172,7 +131,7 @@ const KeyboardShortcut = {
172 131
      * @param shortcutChar unregisters the given shortcut, which means it will
173 132
      * no longer be usable
174 133
      */
175
-    unregisterShortcut: function(shortcutChar) {
134
+    unregisterShortcut(shortcutChar) {
176 135
         _shortcuts.remove(shortcutChar);
177 136
 
178 137
         this._removeShortcutFromHelp(shortcutChar);
@@ -186,44 +145,47 @@ const KeyboardShortcut = {
186 145
      * or an empty string if the shortcutAttr is null, an empty string or not
187 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 151
                 if (_shortcuts.hasOwnProperty(key)
193 152
                     && _shortcuts[key].shortcutAttr
194 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 163
      * @param e a KeyboardEvent
204 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 168
             return e.key;
209 169
         }
210
-        if (e.type === "keypress"
170
+        if (e.type === 'keypress'
211 171
                 && ((e.which >= 32 && e.which <= 126)
212
-                    || (e.which >= 160 && e.which <= 255) )) {
172
+                    || (e.which >= 160 && e.which <= 255))) {
213 173
             return String.fromCharCode(e.which);
214 174
         }
175
+
215 176
         // try to fallback (0-9A-Za-z and QWERTY keyboard)
216 177
         switch (e.which) {
217 178
         case 27:
218
-            return "Escape";
179
+            return 'Escape';
219 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 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,36 +195,41 @@ const KeyboardShortcut = {
233 195
      * @param shortcutDescriptionKey the description of the shortcut
234 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 203
         listElement.className = itemClass;
241 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 213
         kbdElement.className = classes;
249 214
         kbdElement.innerHTML = shortcutChar;
250 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 220
         descriptionElement.className = descriptionClass;
255
-        descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
221
+        descriptionElement.setAttribute('data-i18n', shortcutDescriptionKey);
256 222
         APP.translation.translateElement($(descriptionElement));
257 223
 
258 224
         listElement.appendChild(spanElement);
259 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 231
             parentListElement.appendChild(listElement);
232
+        }
266 233
     },
267 234
 
268 235
     /**
@@ -270,14 +237,57 @@ const KeyboardShortcut = {
270 237
      * help dialog
271 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 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 查看文件

@@ -5,74 +5,76 @@
5 5
  * @enum {string}
6 6
  */
7 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 72
  * Mapping between the key codes and keys deined in KEYS.
72 73
  * The mappings are based on
73 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 78
     8: KEYS.BACKSPACE,
77 79
     9: KEYS.TAB,
78 80
     13: KEYS.RETURN,
@@ -141,15 +143,16 @@ let keyCodeToKey = {
141 143
 /**
142 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 147
     keyCodeToKey[i + 48] = `${i}`;
146 148
 }
147 149
 
148 150
 /**
149 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 156
     keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase();
154 157
 }
155 158
 

+ 7
- 3
modules/recorder/Recorder.js 查看文件

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

+ 52
- 44
modules/settings/Settings.js 查看文件

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

+ 24
- 2
modules/translation/translation.js 查看文件

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

+ 1
- 0
modules/transport/PostMessageTransportBackend.js 查看文件

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

+ 2
- 0
modules/util/JitsiLocalStorage.js 查看文件

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

+ 7
- 5
modules/util/JitsiMeetLogStorage.js 查看文件

@@ -37,15 +37,17 @@ export default class JitsiMeetLogStorage {
37 37
             return;
38 38
         }
39 39
 
40
-        let logJSON = '{"log' + this.counter + '":"\n';
40
+        let logJSON = `{"log${this.counter}":"\n`;
41
+
41 42
         for (let i = 0, len = logEntries.length; i < len; i++) {
42
-            let logEntry = logEntries[i];
43
+            const logEntry = logEntries[i];
44
+
43 45
             if (typeof logEntry === 'object') {
44 46
                 // Aggregated message
45
-                logJSON += '(' + logEntry.count + ') ' + logEntry.text + '\n';
47
+                logJSON += `(${logEntry.count}) ${logEntry.text}\n`;
46 48
             } else {
47 49
                 // Regular message
48
-                logJSON += logEntry + '\n';
50
+                logJSON += `${logEntry}\n`;
49 51
             }
50 52
         }
51 53
         logJSON += '"}';
@@ -60,7 +62,7 @@ export default class JitsiMeetLogStorage {
60 62
         } catch (error) {
61 63
             // NOTE console is intentional here
62 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 查看文件

@@ -1,4 +1,4 @@
1
-const logger = require("jitsi-meet-logger").getLogger(__filename);
1
+const logger = require('jitsi-meet-logger').getLogger(__filename);
2 2
 
3 3
 /**
4 4
  * Create deferred object.
@@ -40,7 +40,7 @@ export function replace(url) {
40 40
  * @param e {Error} the error
41 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 44
     logger.error(msg, e);
45 45
     window.onerror && window.onerror(msg, null, null, null, e);
46 46
 }

+ 0
- 259
react/.eslintrc.js 查看文件

@@ -6,48 +6,12 @@ module.exports = {
6 6
         }
7 7
     },
8 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 9
         'jsdoc',
15 10
         'react',
16 11
         'react-native'
17 12
     ],
18 13
     'rules': {
19 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 16
         // Currently, we are using both valid-jsdoc and 'jsdoc' plugin. In the
53 17
         // future we might stick to one as soon as it has all the features.
@@ -74,234 +38,11 @@ module.exports = {
74 38
                 'requireReturnType': true
75 39
             }
76 40
         ],
77
-        'valid-typeof': 2,
78 41
 
79 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 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 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 47
         // JsDoc plugin rules group. The following rules are in addition to
307 48
         // valid-jsdoc rule.

+ 52
- 43
service/UI/UIEvents.js 查看文件

@@ -1,50 +1,58 @@
1 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 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 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 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 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 32
      * Updates shared video with params: url, state, time(optional)
28 33
      * Where url is the video link, state is stop/start/pause and time is the
29 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 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 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 57
      * Notifies that a command to toggle the filmstrip has been issued. The
50 58
      * event may optionally specify a {Boolean} (primitive) value to assign to
@@ -56,7 +64,8 @@ export default {
56 64
      *
57 65
      * @see {TOGGLED_FILMSTRIP}
58 66
      */
59
-    TOGGLE_FILMSTRIP: "UI.toggle_filmstrip",
67
+    TOGGLE_FILMSTRIP: 'UI.toggle_filmstrip',
68
+
60 69
     /**
61 70
      * Notifies that the filmstrip was (actually) toggled. The event supplies a
62 71
      * {Boolean} (primitive) value indicating the visibility of the filmstrip
@@ -64,59 +73,59 @@ export default {
64 73
      *
65 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 90
      * Notifies interested listeners that the follow-me feature is enabled or
82 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 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 100
     // An event which indicates that the resolution of a remote video has
92 101
     // changed.
93
-    RESOLUTION_CHANGED: "UI.resolution_changed",
102
+    RESOLUTION_CHANGED: 'UI.resolution_changed',
94 103
 
95 104
     /**
96 105
      * Notifies that the button "Cancel" is pressed on the dialog for
97 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 111
      * Notifies that the side toolbar container has been toggled. The actual
103 112
      * event must contain the identifier of the container that has been toggled
104 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 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 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 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 查看文件

@@ -2,7 +2,7 @@
2 2
  * The value for the "var" attribute of feature tag in disco-info packets.
3 3
  */
4 4
 export const DISCO_REMOTE_CONTROL_FEATURE
5
-    = "http://jitsi.org/meet/remotecontrol";
5
+    = 'http://jitsi.org/meet/remotecontrol';
6 6
 
7 7
 /**
8 8
  * Types of remote-control events.
@@ -10,17 +10,17 @@ export const DISCO_REMOTE_CONTROL_FEATURE
10 10
   * @enum {string}
11 11
  */
12 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,7 +29,7 @@ export const EVENTS = {
29 29
   * @enum {string}
30 30
  */
31 31
 export const REQUESTS = {
32
-    start: "start"
32
+    start: 'start'
33 33
 };
34 34
 
35 35
 /**
@@ -38,16 +38,16 @@ export const REQUESTS = {
38 38
  * @enum {string}
39 39
  */
40 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 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 53
  * The remote control event.

+ 22
- 18
static/close.js 查看文件

@@ -1,11 +1,13 @@
1 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,9 +15,9 @@ var hints = [
13 15
  *
14 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 22
     return hints[n];
21 23
 }
@@ -27,28 +29,30 @@ function getHint(){
27 29
  * @param id {string} element identificator
28 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 36
         el.innerHTML = msg;
37
+    }
36 38
 }
37 39
 
38 40
 /**
39 41
  * Sets the hint and thanks messages. Will be executed on load event.
40 42
  */
41 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 45
     insertTextMsg('thanksMessage',
44
-        'Thank you for using ' + interfaceConfig.APP_NAME);
46
+        `Thank you for using ${interfaceConfig.APP_NAME}`);
45 47
 
46 48
     // If there is a setting show a special message only for the guests
47 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 53
             element.classList.add('hide');
51 54
             insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
55
+
52 56
             return;
53 57
         }
54 58
     }

+ 16
- 9
webpack.config.js 查看文件

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

Loading…
取消
儲存