瀏覽代碼

Merge pull request #1008 from jitsi/page_reload_overlay

Page reload overlay
j8
hristoterezov 8 年之前
父節點
當前提交
3dca6f2354

+ 23
- 0
app.js 查看文件

24
 import UI from "./modules/UI/UI";
24
 import UI from "./modules/UI/UI";
25
 import settings from "./modules/settings/Settings";
25
 import settings from "./modules/settings/Settings";
26
 import conference from './conference';
26
 import conference from './conference';
27
+import ConferenceUrl from './modules/URL/ConferenceUrl';
27
 import API from './modules/API/API';
28
 import API from './modules/API/API';
28
 
29
 
29
 import UIEvents from './service/UI/UIEvents';
30
 import UIEvents from './service/UI/UIEvents';
47
     return null;
48
     return null;
48
 }
49
 }
49
 
50
 
51
+/**
52
+ * Replaces current history state(replaces the URL displayed by the browser).
53
+ * @param {string} newUrl the URL string which is to be displayed by the browser
54
+ * to the user.
55
+ */
56
+function replaceHistoryState (newUrl) {
57
+    if (window.history
58
+        && typeof window.history.replaceState === 'function') {
59
+        window.history.replaceState({}, document.title, newUrl);
60
+    }
61
+}
62
+
50
 /**
63
 /**
51
  * Builds and returns the room name.
64
  * Builds and returns the room name.
52
  */
65
  */
82
     UI,
95
     UI,
83
     settings,
96
     settings,
84
     conference,
97
     conference,
98
+    /**
99
+     * After the APP has been initialized provides utility methods for dealing
100
+     * with the conference room URL(address).
101
+     * @type ConferenceUrl
102
+     */
103
+    ConferenceUrl : null,
85
     connection: null,
104
     connection: null,
86
     API,
105
     API,
87
     init () {
106
     init () {
107
 
126
 
108
 function init() {
127
 function init() {
109
     setTokenData();
128
     setTokenData();
129
+    // Initialize the conference URL handler
130
+    APP.ConferenceUrl = new ConferenceUrl(window.location);
131
+    // Clean up the URL displayed by the browser
132
+    replaceHistoryState(APP.ConferenceUrl.getInviteUrl());
110
     var isUIReady = APP.UI.start();
133
     var isUIReady = APP.UI.start();
111
     if (isUIReady) {
134
     if (isUIReady) {
112
         APP.conference.init({roomName: buildRoomName()}).then(function () {
135
         APP.conference.init({roomName: buildRoomName()}).then(function () {

+ 14
- 5
conference.js 查看文件

329
             }
329
             }
330
             break;
330
             break;
331
 
331
 
332
-        case ConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE:
333
-            APP.UI.notifyBridgeDown();
334
-            break;
335
-
336
             // not enough rights to create conference
332
             // not enough rights to create conference
337
         case ConferenceErrors.AUTHENTICATION_REQUIRED:
333
         case ConferenceErrors.AUTHENTICATION_REQUIRED:
338
             // schedule reconnect to check if someone else created the room
334
             // schedule reconnect to check if someone else created the room
367
             }
363
             }
368
             break;
364
             break;
369
 
365
 
366
+            // FIXME FOCUS_DISCONNECTED is confusing event name.
367
+            // What really happens there is that the library is not ready yet,
368
+            // because Jicofo is not available, but it is going to give
369
+            // it another try.
370
         case ConferenceErrors.FOCUS_DISCONNECTED:
370
         case ConferenceErrors.FOCUS_DISCONNECTED:
371
             {
371
             {
372
                 let [focus, retrySec] = params;
372
                 let [focus, retrySec] = params;
375
             break;
375
             break;
376
 
376
 
377
         case ConferenceErrors.FOCUS_LEFT:
377
         case ConferenceErrors.FOCUS_LEFT:
378
+        case ConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE:
379
+            // Log the page reload event
380
+            // FIXME (CallStats - issue) this event will not make it to
381
+            // the CallStats, because the log queue is not flushed, before
382
+            // "fabric terminated" is sent to the backed
383
+            APP.conference.logEvent('page.reload');
384
+            // FIXME the conference should be stopped by the library and not by
385
+            // the app. Both the errors above are unrecoverable from the library
386
+            // perspective.
378
             room.leave().then(() => connection.disconnect());
387
             room.leave().then(() => connection.disconnect());
379
-            APP.UI.notifyFocusLeft();
388
+            APP.UI.showPageReloadOverlay();
380
             break;
389
             break;
381
 
390
 
382
         case ConferenceErrors.CONFERENCE_MAX_USERS:
391
         case ConferenceErrors.CONFERENCE_MAX_USERS:

+ 2
- 1
css/_variables.scss 查看文件

84
  */
84
  */
85
 $tooltipsZ: 901;
85
 $tooltipsZ: 901;
86
 $toolbarZ: 900;
86
 $toolbarZ: 900;
87
-$overlayZ: 800;
87
+$overlayZ: 902;
88
 $notificationZ: 1012;
88
 $notificationZ: 1012;
89
+$ringingZ: 800;
89
 
90
 
90
 /**
91
 /**
91
  * Font Colors TODO: Change colors when general dialogs are implemented.
92
  * Font Colors TODO: Change colors when general dialogs are implemented.

+ 1
- 0
css/main.scss 查看文件

38
 @import 'toastr';
38
 @import 'toastr';
39
 @import 'base';
39
 @import 'base';
40
 @import 'overlay/overlay';
40
 @import 'overlay/overlay';
41
+@import 'reload_overlay/reload_overlay';
41
 @import 'modals/dialog';
42
 @import 'modals/dialog';
42
 @import 'modals/feedback/feedback';
43
 @import 'modals/feedback/feedback';
43
 @import 'videolayout_default';
44
 @import 'videolayout_default';

+ 5
- 23
css/overlay/_overlay.scss 查看文件

1
-.overlay {
2
-    position: fixed;
3
-    left: 0;
4
-    top: 0;
5
-    width: 100%;
6
-    height: 100%;
7
-    z-index: $overlayZ;
8
-    background: #21B9FC; /* Old browsers */
9
-    opacity: 0.75;
10
-    display: block;
11
-}
12
-
13
-.overlay_transparent {
14
-    background: rgba(22, 185, 252, .9);
15
-}
16
-
17
 .overlay_container {
1
 .overlay_container {
2
+    top: 0;
3
+    left: 0;
18
     width: 100%;
4
     width: 100%;
19
     height: 100%;
5
     height: 100%;
20
     position: fixed;
6
     position: fixed;
21
     z-index: $overlayZ;
7
     z-index: $overlayZ;
8
+    background: rgba(22, 185, 252, .9);
22
 }
9
 }
23
 
10
 
24
 .overlay_content {
11
 .overlay_content {
25
     color: #fff;
12
     color: #fff;
26
-    font-weight: normal;
27
-    font-size: 20px;
28
     text-align: center;
13
     text-align: center;
29
     width: 400px;
14
     width: 400px;
30
     height: 250px;
15
     height: 250px;
31
     top: 50%;
16
     top: 50%;
32
     left: 50%;
17
     left: 50%;
33
-    position:absolute;
18
+    position: absolute;
34
     margin-top: -125px;
19
     margin-top: -125px;
35
     margin-left: -200px;
20
     margin-left: -200px;
36
 }
21
 }
37
 
22
 
38
-
39
 .overlay_text_small {
23
 .overlay_text_small {
24
+    display: block;
40
     font-size: 18px;
25
     font-size: 18px;
41
 }
26
 }
42
 
27
 
43
 .overlay_icon {
28
 .overlay_icon {
44
-    position: relative;
45
-    z-index: 1013;
46
-    float: none;
47
     font-size: 100px;
29
     font-size: 100px;
48
 }
30
 }

+ 17
- 0
css/reload_overlay/_reload_overlay.scss 查看文件

1
+.reload_overlay_title {
2
+    display: block;
3
+    font-size: 16px;
4
+    line-height: 20px;
5
+}
6
+
7
+.reload_overlay_msg {
8
+    display: block;
9
+    font-size: 12px;
10
+    line-height: 30px;
11
+}
12
+
13
+#reloadProgressBar {
14
+    width: 180px;
15
+    margin: 5px auto;
16
+}
17
+

+ 1
- 1
css/ringing/_ringing.scss 查看文件

5
     width: 100%;
5
     width: 100%;
6
     height: 100%;
6
     height: 100%;
7
     position: fixed;
7
     position: fixed;
8
-    z-index: $overlayZ;
8
+    z-index: $ringingZ;
9
     background: linear-gradient(transparent, #000);
9
     background: linear-gradient(transparent, #000);
10
     opacity: 0.8;
10
     opacity: 0.8;
11
 
11
 

+ 3
- 2
lang/main.json 查看文件

202
         "detectext": "Error when trying to detect desktopsharing extension.",
202
         "detectext": "Error when trying to detect desktopsharing extension.",
203
         "failtoinstall": "Failed to install desktop sharing extension",
203
         "failtoinstall": "Failed to install desktop sharing extension",
204
         "failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.",
204
         "failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.",
205
-        "bridgeUnavailable": "Jitsi Videobridge is currently unavailable. Please try again later!",
206
-        "jicofoUnavailable": "Jicofo is currently unavailable. Please try again later!",
205
+        "conferenceReloadTitle": "Unfortunately, something went wrong",
206
+        "conferenceReloadMsg": "We're trying to fix this",
207
+        "conferenceReloadTimeLeft": "__seconds__ sec.",
207
         "maxUsersLimitReached": "The limit for maximum number of participants in the conference has been reached. The conference is full. Please try again later!",
208
         "maxUsersLimitReached": "The limit for maximum number of participants in the conference has been reached. The conference is full. Please try again later!",
208
         "lockTitle": "Lock failed",
209
         "lockTitle": "Lock failed",
209
         "lockMessage": "Failed to lock the conference.",
210
         "lockMessage": "Failed to lock the conference.",

+ 17
- 39
modules/UI/UI.js 查看文件

14
 import GumPermissionsOverlay
14
 import GumPermissionsOverlay
15
     from './gum_overlay/UserMediaPermissionsGuidanceOverlay';
15
     from './gum_overlay/UserMediaPermissionsGuidanceOverlay';
16
 
16
 
17
+import PageReloadOverlay from './reload_overlay/PageReloadOverlay';
17
 import VideoLayout from "./videolayout/VideoLayout";
18
 import VideoLayout from "./videolayout/VideoLayout";
18
 import FilmStrip from "./videolayout/FilmStrip";
19
 import FilmStrip from "./videolayout/FilmStrip";
19
 import SettingsMenu from "./side_pannels/settings/SettingsMenu";
20
 import SettingsMenu from "./side_pannels/settings/SettingsMenu";
20
 import Profile from "./side_pannels/profile/Profile";
21
 import Profile from "./side_pannels/profile/Profile";
21
 import Settings from "./../settings/Settings";
22
 import Settings from "./../settings/Settings";
22
-import { reload } from '../util/helpers';
23
 import RingOverlay from "./ring_overlay/RingOverlay";
23
 import RingOverlay from "./ring_overlay/RingOverlay";
24
 import UIErrors from './UIErrors';
24
 import UIErrors from './UIErrors';
25
 
25
 
195
     messageHandler.openDialog(title, reason, true, {}, () => false);
195
     messageHandler.openDialog(title, reason, true, {}, () => false);
196
 };
196
 };
197
 
197
 
198
-/**
199
- * Notify user that Jitsi Videobridge is not accessible.
200
- */
201
- UI.notifyBridgeDown = function () {
202
-    messageHandler.showError("dialog.error", "dialog.bridgeUnavailable");
203
-};
204
-
205
 /**
198
 /**
206
  * Show chat error.
199
  * Show chat error.
207
  * @param err the Error
200
  * @param err the Error
265
  */
258
  */
266
 UI.initConference = function () {
259
 UI.initConference = function () {
267
     let id = APP.conference.getMyUserId();
260
     let id = APP.conference.getMyUserId();
268
-
269
-    // Do not include query parameters in the invite URL
270
-    // "https:" + "//" + "example.com:8888" + "/SomeConference1245"
271
-    var inviteURL = window.location.protocol + "//" +
272
-        window.location.host + window.location.pathname;
273
-
274
-    this.emitEvent(UIEvents.INVITE_URL_INITIALISED, inviteURL);
275
-
276
-    // Clean up the URL displayed by the browser
277
-    if (window.history && typeof window.history.replaceState === 'function') {
278
-        window.history.replaceState({}, document.title, inviteURL);
279
-    }
280
-
281
     // Add myself to the contact list.
261
     // Add myself to the contact list.
282
     UI.ContactList.addContact(id, true);
262
     UI.ContactList.addContact(id, true);
283
 
263
 
1119
 };
1099
 };
1120
 
1100
 
1121
 /**
1101
 /**
1122
- * Notify user that focus left the conference so page should be reloaded.
1102
+ * Notify the user that the video conferencing service is badly broken and
1103
+ * the page should be reloaded.
1123
  */
1104
  */
1124
-UI.notifyFocusLeft = function () {
1125
-    let title = APP.translation.generateTranslationHTML(
1126
-        'dialog.serviceUnavailable'
1127
-    );
1128
-    let msg = APP.translation.generateTranslationHTML(
1129
-        'dialog.jicofoUnavailable'
1130
-    );
1131
-    messageHandler.openDialog(
1132
-        title,
1133
-        msg,
1134
-        true, // persistent
1135
-        [{title: 'retry'}],
1136
-        function () {
1137
-            reload();
1138
-            return false;
1139
-        }
1140
-    );
1105
+UI.showPageReloadOverlay = function () {
1106
+    PageReloadOverlay.show(15 /* will reload in 15 seconds */);
1141
 };
1107
 };
1142
 
1108
 
1143
 /**
1109
 /**
1475
     FilmStrip.toggleFilmStrip(true);
1441
     FilmStrip.toggleFilmStrip(true);
1476
 };
1442
 };
1477
 
1443
 
1444
+/**
1445
+ * Indicates if any the "top" overlays are currently visible. The check includes
1446
+ * the call overlay, GUM permissions overlay and a page reload overlay.
1447
+ *
1448
+ * @returns {*|boolean} {true} if the overlay is visible, {false} otherwise
1449
+ */
1450
+UI.isOverlayVisible = function () {
1451
+    return RingOverlay.isVisible()
1452
+        || PageReloadOverlay.isVisible()
1453
+        || GumPermissionsOverlay.isVisible();
1454
+};
1455
+
1478
 /**
1456
 /**
1479
  * Indicates if the ring overlay is currently visible.
1457
  * Indicates if the ring overlay is currently visible.
1480
  *
1458
  *

+ 44
- 22
modules/UI/gum_overlay/UserMediaPermissionsGuidanceOverlay.js 查看文件

1
-/* global $, APP */
1
+/* global */
2
 
2
 
3
-let $overlay;
3
+import Overlay from '../overlay/Overlay';
4
 
4
 
5
 /**
5
 /**
6
- * Internal function that constructs overlay with guidance how to proceed with
7
- * gUM prompt.
8
- * @param {string} browser - name of browser for which to construct the
9
- *      guidance overlay.
6
+ * An overlay with guidance how to proceed with gUM prompt.
10
  */
7
  */
11
-function buildOverlayHtml(browser) {
12
-    $overlay = $(`
13
-        <div class='overlay_container'>
14
-            <div class='overlay overlay_transparent' />
15
-            <div class='overlay_content'>
16
-                <span class="overlay_icon icon-microphone"></span>
17
-                <span class="overlay_icon icon-camera"></span>
18
-                <span data-i18n='[html]userMedia.${browser}GrantPermissions' 
19
-                    class='overlay_text overlay_text_small'></span>
20
-            </div>
21
-        </div>`);
8
+class GUMOverlayImpl extends Overlay {
22
 
9
 
23
-    APP.translation.translateElement($overlay);
10
+    /**
11
+     * Constructs overlay with guidance how to proceed with gUM prompt.
12
+     * @param {string} browser - name of browser for which to construct the
13
+     *     guidance overlay.
14
+     * @override
15
+     */
16
+    constructor(browser) {
17
+        super();
18
+        this.browser = browser;
19
+    }
20
+
21
+    /**
22
+     * @inheritDoc
23
+     */
24
+    _buildOverlayContent() {
25
+        return `
26
+            <span class="overlay_icon icon-microphone"></span>
27
+            <span class="overlay_icon icon-camera"></span>
28
+            <span data-i18n='[html]userMedia.${this.browser}GrantPermissions' 
29
+                  class='overlay_text_small'></span>`;
30
+    }
24
 }
31
 }
25
 
32
 
33
+/**
34
+ * Stores GUM overlay instance.
35
+ * @type {GUMOverlayImpl}
36
+ */
37
+let overlay;
38
+
26
 export default {
39
 export default {
40
+    /**
41
+     * Checks whether the overlay is currently visible.
42
+     * @return {boolean} <tt>true</tt> if the overlay is visible
43
+     * or <tt>false</tt> otherwise.
44
+     */
45
+    isVisible () {
46
+        return overlay && overlay.isVisible();
47
+    },
27
     /**
48
     /**
28
      * Shows browser-specific overlay with guidance how to proceed with
49
      * Shows browser-specific overlay with guidance how to proceed with
29
      * gUM prompt.
50
      * gUM prompt.
31
      *      guidance overlay.
52
      *      guidance overlay.
32
      */
53
      */
33
     show(browser) {
54
     show(browser) {
34
-        !$overlay && buildOverlayHtml(browser);
35
-
36
-        !$overlay.parents('body').length && $overlay.appendTo('body');
55
+        if (!overlay) {
56
+            overlay = new GUMOverlayImpl(browser);
57
+        }
58
+        overlay.show();
37
     },
59
     },
38
 
60
 
39
     /**
61
     /**
41
      * gUM prompt.
63
      * gUM prompt.
42
      */
64
      */
43
     hide() {
65
     hide() {
44
-        $overlay && $overlay.detach();
66
+        overlay && overlay.hide();
45
     }
67
     }
46
 };
68
 };

+ 1
- 13
modules/UI/invite/Invite.js 查看文件

14
 class Invite {
14
 class Invite {
15
     constructor(conference) {
15
     constructor(conference) {
16
         this.conference = conference;
16
         this.conference = conference;
17
+        this.inviteUrl = APP.ConferenceUrl.getInviteUrl();
17
         this.createRoomLocker(conference);
18
         this.createRoomLocker(conference);
18
         this.registerListeners();
19
         this.registerListeners();
19
     }
20
     }
48
         APP.UI.addListener( UIEvents.INVITE_CLICKED,
49
         APP.UI.addListener( UIEvents.INVITE_CLICKED,
49
                             () => { this.openLinkDialog(); });
50
                             () => { this.openLinkDialog(); });
50
 
51
 
51
-        APP.UI.addListener( UIEvents.INVITE_URL_INITIALISED,
52
-                            (inviteUrl) => {
53
-                                this.updateInviteUrl(inviteUrl);
54
-                            });
55
-
56
         APP.UI.addListener( UIEvents.PASSWORD_REQUIRED,
52
         APP.UI.addListener( UIEvents.PASSWORD_REQUIRED,
57
             () => {
53
             () => {
58
                 this.setLockedFromElsewhere(true);
54
                 this.setLockedFromElsewhere(true);
172
         }
168
         }
173
     }
169
     }
174
 
170
 
175
-    /**
176
-     * Updates the room invite url.
177
-     */
178
-    updateInviteUrl (newInviteUrl) {
179
-        this.inviteUrl = newInviteUrl;
180
-        this.updateView();
181
-    }
182
-
183
     /**
171
     /**
184
      * Helper method for encoding
172
      * Helper method for encoding
185
      * Invite URL
173
      * Invite URL

+ 82
- 0
modules/UI/overlay/Overlay.js 查看文件

1
+/* global $, APP */
2
+
3
+/**
4
+ * Base class for overlay components - the components which are displayed on
5
+ * top of the application with semi-transparent background covering the whole
6
+ * screen.
7
+ */
8
+export default class Overlay{
9
+    /**
10
+     * Creates new <tt>Overlay</tt> instance.
11
+     */
12
+    constructor() {
13
+        /**
14
+         *
15
+         * @type {jQuery}
16
+         */
17
+        this.$overlay = null;
18
+    }
19
+    /**
20
+     * Template method which should be used by subclasses to provide the overlay
21
+     * content. The contents provided by this method are later subject to
22
+     * the translation using {@link APP.translation.translateElement}.
23
+     * @return {string} HTML representation of the overlay dialog contents.
24
+     * @private
25
+     */
26
+    _buildOverlayContent() {
27
+        return '';
28
+    }
29
+    /**
30
+     * Constructs the HTML body of the overlay dialog.
31
+     */
32
+    buildOverlayHtml() {
33
+
34
+        let overlayContent = this._buildOverlayContent();
35
+
36
+        this.$overlay = $(`
37
+            <div class='overlay_container'>
38
+                <div class='overlay_content'>
39
+                    ${overlayContent}
40
+                </div>
41
+            </div>`);
42
+
43
+        APP.translation.translateElement(this.$overlay);
44
+    }
45
+    /**
46
+     * Checks whether the page reload overlay has been displayed.
47
+     * @return {boolean} <tt>true</tt> if the page reload overlay is currently
48
+     * visible or <tt>false</tt> otherwise.
49
+     */
50
+    isVisible() {
51
+        return this.$overlay && this.$overlay.parents('body').length > 0;
52
+    }
53
+    /**
54
+     * Template method called just after the overlay is displayed for the first
55
+     * time.
56
+     * @private
57
+     */
58
+    _onShow() {
59
+        // To be overridden by subclasses.
60
+    }
61
+    /**
62
+     * Shows the overlay dialog adn attaches the underlying HTML representation
63
+     * to the DOM.
64
+     */
65
+    show() {
66
+
67
+        !this.$overlay && this.buildOverlayHtml();
68
+
69
+        if (!this.isVisible()) {
70
+            this.$overlay.appendTo('body');
71
+            this._onShow();
72
+        }
73
+    }
74
+
75
+    /**
76
+     * Hides the overlay dialog and detaches it's HTML representation from
77
+     * the DOM.
78
+     */
79
+    hide() {
80
+        this.$overlay && this.$overlay.detach();
81
+    }
82
+}

+ 122
- 0
modules/UI/reload_overlay/PageReloadOverlay.js 查看文件

1
+/* global $, APP, AJS */
2
+
3
+import Overlay from '../overlay/Overlay';
4
+
5
+/**
6
+ * An overlay dialog which is shown before the conference is reloaded. Shows
7
+ * a warning message and counts down towards the reload.
8
+ */
9
+class PageReloadOverlayImpl extends Overlay{
10
+    /**
11
+     * Creates new <tt>PageReloadOverlayImpl</tt>
12
+     * @param {number} timeoutSeconds how long the overlay dialog will be
13
+     * displayed, before the conference will be reloaded.
14
+     */
15
+    constructor(timeoutSeconds) {
16
+        super();
17
+        /**
18
+         * Conference reload counter in seconds.
19
+         * @type {number}
20
+         */
21
+        this.timeLeft = timeoutSeconds;
22
+        /**
23
+         * Conference reload timeout in seconds.
24
+         * @type {number}
25
+         */
26
+        this.timeout = timeoutSeconds;
27
+    }
28
+    /**
29
+     * Constructs overlay body with the warning message and count down towards
30
+     * the conference reload.
31
+     * @override
32
+     */
33
+    _buildOverlayContent() {
34
+        return `
35
+            <span data-i18n='dialog.conferenceReloadTitle' 
36
+                  class='reload_overlay_title'></span>
37
+            <span data-i18n='dialog.conferenceReloadMsg' 
38
+                  class='reload_overlay_msg'></span>
39
+            <div>
40
+                <div id='reloadProgressBar' class="aui-progress-indicator">
41
+                    <span class="aui-progress-indicator-value"></span>
42
+                </div>
43
+                <span id='reloadSecRemaining' class='reload_overlay_msg'>
44
+                </span>
45
+            </div>`;
46
+    }
47
+
48
+    /**
49
+     * Updates the progress indicator position and the label with the time left.
50
+     */
51
+    updateDisplay() {
52
+
53
+        const timeLeftTxt
54
+            = APP.translation.translateString(
55
+                "dialog.conferenceReloadTimeLeft",
56
+                { seconds: this.timeLeft });
57
+        $("#reloadSecRemaining").text(timeLeftTxt);
58
+
59
+        const ratio = (this.timeout - this.timeLeft) / this.timeout;
60
+        AJS.progressBars.update("#reloadProgressBar", ratio);
61
+    }
62
+
63
+    /**
64
+     * Starts the reload countdown with the animation.
65
+     * @override
66
+     */
67
+    _onShow() {
68
+
69
+        // Initialize displays
70
+        this.updateDisplay();
71
+
72
+        var intervalId = window.setInterval(function() {
73
+
74
+            if (this.timeLeft >= 1) {
75
+                this.timeLeft -= 1;
76
+            }
77
+
78
+            this.updateDisplay();
79
+
80
+            if (this.timeLeft === 0) {
81
+                window.clearInterval(intervalId);
82
+                APP.ConferenceUrl.reload();
83
+            }
84
+        }.bind(this), 1000);
85
+
86
+        console.info(
87
+            "The conference will be reloaded after "
88
+                + this.timeLeft + " seconds.");
89
+    }
90
+}
91
+
92
+/**
93
+ * Holds the page reload overlay instance.
94
+ *
95
+ * {@type PageReloadOverlayImpl}
96
+ */
97
+let overlay;
98
+
99
+export default {
100
+    /**
101
+     * Checks whether the page reload overlay has been displayed.
102
+     * @return {boolean} <tt>true</tt> if the page reload overlay is currently
103
+     * visible or <tt>false</tt> otherwise.
104
+     */
105
+    isVisible() {
106
+        return overlay && overlay.isVisible();
107
+    },
108
+    /**
109
+     * Shows the page reload overlay which will do the conference reload after
110
+     * the given amount of time.
111
+     *
112
+     * @param {number} timeoutSeconds how many seconds before the conference
113
+     * reload will happen.
114
+     */
115
+    show(timeoutSeconds) {
116
+
117
+        if (!overlay) {
118
+            overlay = new PageReloadOverlayImpl(timeoutSeconds);
119
+        }
120
+        overlay.show();
121
+    }
122
+};

+ 4
- 3
modules/UI/toolbars/ToolbarToggler.js 查看文件

34
     clearTimeout(toolbarTimeoutObject);
34
     clearTimeout(toolbarTimeoutObject);
35
     toolbarTimeoutObject = null;
35
     toolbarTimeoutObject = null;
36
 
36
 
37
-    if (Toolbar.isHovered()
38
-            || APP.UI.isRingOverlayVisible()
39
-            || SideContainerToggler.isVisible()) {
37
+    if (force !== true &&
38
+            (Toolbar.isHovered()
39
+                || APP.UI.isRingOverlayVisible()
40
+                || SideContainerToggler.isVisible())) {
40
         toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
41
         toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
41
     } else {
42
     } else {
42
         Toolbar.hide();
43
         Toolbar.hide();

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

333
                      messageArguments, options) {
333
                      messageArguments, options) {
334
 
334
 
335
         // If we're in ringing state we skip all toaster notifications.
335
         // If we're in ringing state we skip all toaster notifications.
336
-        if(!notificationsEnabled || APP.UI.isRingOverlayVisible())
336
+        if(!notificationsEnabled || APP.UI.isOverlayVisible())
337
             return;
337
             return;
338
 
338
 
339
         var displayNameSpan = '<span class="nickname" ';
339
         var displayNameSpan = '<span class="nickname" ';

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

1
+/* global console */
2
+
3
+import { redirect } from '../util/helpers';
4
+
5
+/**
6
+ * The modules stores information about the URL used to start the conference and
7
+ * provides utility methods for dealing with conference URL and reloads.
8
+ */
9
+export default class ConferenceUrl {
10
+    /**
11
+     * Initializes the module.
12
+     *
13
+     * @param location an object which stores provides the info about conference
14
+     * URL(would be 'window.location' for the Web app). The params below are
15
+     * described based on the following example URL:
16
+     *
17
+     * https://example.com:8888/SomeConference1245?opt=1#somehash
18
+     *
19
+     * @param location.href full URL with all parameters, would be the whole URL
20
+     * from the example string above.
21
+     *
22
+     * @param location.host the host part of the URL, 'example.com' from
23
+     * the sample URL above.
24
+     *
25
+     * @param location.pathname the path part of the URL, would be
26
+     * '/SomeConference1245' from the example above.
27
+     *
28
+     * @param location.protocol the protocol part of the URL, would be 'https:'
29
+     * from the sample URL.
30
+     */
31
+    constructor(location) {
32
+        /**
33
+         * Stores the original conference room URL with all parameters.
34
+         * Example:
35
+         * https://example.com:8888/SomeConference1245?jwt=a5sbc2#blablahash
36
+         * @type {string}
37
+         */
38
+        this.originalURL = location.href;
39
+        /**
40
+         * A simplified version of the conference URL stripped out of
41
+         * the parameters which should be used for sending invites.
42
+         * Example:
43
+         * https://example.com:8888/SomeConference1245
44
+         * @type {string}
45
+         */
46
+        this.inviteURL
47
+            = location.protocol + "//" + location.host + location.pathname;
48
+        console.info("Stored original conference URL: " + this.originalURL);
49
+        console.info("Conference URL for invites: " + this.inviteURL);
50
+    }
51
+    /**
52
+     * Obtains the conference invite URL.
53
+     * @return {string} the URL pointing o the conference which is mean to be
54
+     * used to invite new participants.
55
+     */
56
+    getInviteUrl() {
57
+        return this.inviteURL;
58
+    }
59
+    /**
60
+     * Obtains full conference URL with all original parameters.
61
+     * @return {string} the original URL used to open the current conference.
62
+     */
63
+    getOriginalUrl() {
64
+        return this.originalURL;
65
+    }
66
+    /**
67
+     * Reloads the conference using original URL with all of the parameters.
68
+     */
69
+    reload() {
70
+        console.info("Reloading the conference using URL: " + this.originalURL);
71
+        redirect(this.originalURL);
72
+    }
73
+}

+ 9
- 0
modules/util/helpers.js 查看文件

20
     window.location.reload();
20
     window.location.reload();
21
 }
21
 }
22
 
22
 
23
+/**
24
+ * Redirects to new URL.
25
+ * @param {string} url the URL pointing to the location where the user should
26
+ * be redirected to.
27
+ */
28
+export function redirect (url) {
29
+    window.location.replace(url);
30
+}
31
+
23
 /**
32
 /**
24
  * Prints the error and reports it to the global error handler.
33
  * Prints the error and reports it to the global error handler.
25
  * @param e {Error} the error
34
  * @param e {Error} the error

+ 0
- 5
service/UI/UIEvents.js 查看文件

145
      */
145
      */
146
     DISPLAY_NAME_CHANGED: "UI.display_name_changed",
146
     DISPLAY_NAME_CHANGED: "UI.display_name_changed",
147
 
147
 
148
-    /**
149
-     * Indicates that the invite url has been initialised.
150
-     */
151
-    INVITE_URL_INITIALISED: "UI.invite_url_initialised",
152
-
153
     /**
148
     /**
154
      * Indicates that a password is required for the call.
149
      * Indicates that a password is required for the call.
155
      */
150
      */

Loading…
取消
儲存