Browse Source

moved app initialization to react app

master
Ilya Daynatovich 9 years ago
parent
commit
c570b80d7b

+ 1
- 107
app.js View File

@@ -1,4 +1,4 @@
1
-/* global $, config, getRoomName, loggingConfig, JitsiMeetJS */
1
+/* global $, config, loggingConfig, JitsiMeetJS */
2 2
 /* application specific logic */
3 3
 const logger = require("jitsi-meet-logger").getLogger(__filename);
4 4
 
@@ -23,9 +23,6 @@ const LogCollector = Logger.LogCollector;
23 23
 import JitsiMeetLogStorage from "./modules/util/JitsiMeetLogStorage";
24 24
 
25 25
 import URLProcessor from "./modules/config/URLProcessor";
26
-import {
27
-    generateRoomWithoutSeparator
28
-} from './react/features/base/util/roomnameGenerator';
29 26
 
30 27
 import UI from "./modules/UI/UI";
31 28
 import settings from "./modules/settings/Settings";
@@ -33,59 +30,9 @@ import conference from './conference';
33 30
 import ConferenceUrl from './modules/URL/ConferenceUrl';
34 31
 import API from './modules/API/API';
35 32
 
36
-import UIEvents from './service/UI/UIEvents';
37 33
 import getTokenData from "./modules/tokendata/TokenData";
38 34
 import translation from "./modules/translation/translation";
39 35
 
40
-const ConferenceEvents = JitsiMeetJS.events.conference;
41
-
42
-/**
43
- * Tries to push history state with the following parameters:
44
- * 'VideoChat', `Room: ${roomName}`, URL. If fail, prints the error and returns
45
- * it.
46
- */
47
-function pushHistoryState(roomName, URL) {
48
-    try {
49
-        window.history.pushState(
50
-            'VideoChat', `Room: ${roomName}`, URL
51
-        );
52
-    } catch (e) {
53
-        logger.warn("Push history state failed with parameters:",
54
-            'VideoChat', `Room: ${roomName}`, URL, e);
55
-        return e;
56
-    }
57
-    return null;
58
-}
59
-
60
-/**
61
- * Replaces current history state(replaces the URL displayed by the browser).
62
- * @param {string} newUrl the URL string which is to be displayed by the browser
63
- * to the user.
64
- */
65
-function replaceHistoryState (newUrl) {
66
-    if (window.history
67
-        && typeof window.history.replaceState === 'function') {
68
-        window.history.replaceState({}, document.title, newUrl);
69
-    }
70
-}
71
-
72
-/**
73
- * Builds and returns the room name.
74
- */
75
-function buildRoomName () {
76
-    let roomName = getRoomName();
77
-
78
-    if(!roomName) {
79
-        let word = generateRoomWithoutSeparator();
80
-        roomName = word.toLowerCase();
81
-        let historyURL = window.location.href + word;
82
-        //Trying to push state with current URL + roomName
83
-        pushHistoryState(word, historyURL);
84
-    }
85
-
86
-    return roomName;
87
-}
88
-
89 36
 /**
90 37
  * Adjusts the logging levels.
91 38
  * @private
@@ -191,8 +138,6 @@ function init() {
191 138
     setTokenData();
192 139
     // Initialize the conference URL handler
193 140
     APP.ConferenceUrl = new ConferenceUrl(window.location);
194
-    // Clean up the URL displayed by the browser
195
-    replaceHistoryState(APP.ConferenceUrl.getInviteUrl());
196 141
 
197 142
     // TODO The execution of the mobile app starts from react/index.native.js.
198 143
     // Similarly, the execution of the Web app should start from
@@ -201,54 +146,6 @@ function init() {
201 146
     // into the Web app, allow the execution of the Web app to start from app.js
202 147
     // in order to reduce the complexity of the beginning step.
203 148
     require('./react');
204
-
205
-    const isUIReady = APP.UI.start();
206
-    if (isUIReady) {
207
-        APP.conference.init({roomName: buildRoomName()}).then(() => {
208
-
209
-            if (APP.logCollector) {
210
-                // Start the LogCollector's periodic "store logs" task only if
211
-                // we're in the conference and not on the welcome page. This is
212
-                // determined by the value of "isUIReady" const above.
213
-                APP.logCollector.start();
214
-                APP.logCollectorStarted = true;
215
-                // Make an attempt to flush in case a lot of logs have been
216
-                // cached, before the collector was started.
217
-                APP.logCollector.flush();
218
-
219
-                // This event listener will flush the logs, before
220
-                // the statistics module (CallStats) is stopped.
221
-                //
222
-                // NOTE The LogCollector is not stopped, because this event can
223
-                // be triggered multiple times during single conference
224
-                // (whenever statistics module is stopped). That includes
225
-                // the case when Jicofo terminates the single person left in the
226
-                // room. It will then restart the media session when someone
227
-                // eventually join the room which will start the stats again.
228
-                APP.conference.addConferenceListener(
229
-                    ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
230
-                    () => {
231
-                        if (APP.logCollector) {
232
-                            APP.logCollector.flush();
233
-                        }
234
-                    }
235
-                );
236
-            }
237
-
238
-            APP.UI.initConference();
239
-
240
-            APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
241
-                APP.translation.setLanguage(language);
242
-                APP.settings.setLanguage(language);
243
-            });
244
-
245
-            APP.keyboardshortcut.init();
246
-        }).catch(err => {
247
-            APP.UI.hideRingOverLay();
248
-            APP.API.notifyConferenceLeft(APP.conference.roomName);
249
-            logger.error(err);
250
-        });
251
-    }
252 149
 }
253 150
 
254 151
 /**
@@ -295,9 +192,6 @@ $(document).ready(function () {
295 192
     URLProcessor.setConfigParametersFromUrl();
296 193
 
297 194
     APP.init();
298
-
299
-    APP.translation.init(settings.getLanguage());
300
-
301 195
     APP.API.init(APP.tokenData.externalAPISettings);
302 196
 
303 197
     obtainConfigAndInit();

+ 0
- 14
modules/UI/UI.js View File

@@ -396,20 +396,6 @@ UI.getSharedVideoManager = function () {
396 396
  */
397 397
 UI.start = function () {
398 398
     document.title = interfaceConfig.APP_NAME;
399
-    var setupWelcomePage = null;
400
-    if(config.enableWelcomePage && window.location.pathname == "/" &&
401
-       Settings.isWelcomePageEnabled()) {
402
-        $("#videoconference_page").hide();
403
-        if (!setupWelcomePage)
404
-            setupWelcomePage = require("./welcome_page/WelcomePage");
405
-        setupWelcomePage();
406
-
407
-        // Return false to indicate that the UI hasn't been fully started and
408
-        // conference ready. We're still waiting for input from the user.
409
-        return false;
410
-    }
411
-
412
-    $("#welcome_page").hide();
413 399
 
414 400
     // Set the defaults for prompt dialogs.
415 401
     $.prompt.setDefaults({persistent: false});

+ 1
- 1
react/features/app/components/AbstractApp.js View File

@@ -42,7 +42,7 @@ export class AbstractApp extends Component {
42 42
          * The URL, if any, with which the app was launched.
43 43
          */
44 44
         url: React.PropTypes.string
45
-    }
45
+    };
46 46
 
47 47
     /**
48 48
      * Init lib-jitsi-meet and create local participant when component is going

+ 46
- 24
react/features/app/components/App.web.js View File

@@ -1,5 +1,7 @@
1
+/* global APP, $ */
1 2
 import React from 'react';
2 3
 import { Provider } from 'react-redux';
4
+import { compose } from 'redux';
3 5
 import {
4 6
     browserHistory,
5 7
     Route,
@@ -11,6 +13,7 @@ import { getDomain } from '../../base/connection';
11 13
 import { RouteRegistry } from '../../base/navigator';
12 14
 
13 15
 import { AbstractApp } from './AbstractApp';
16
+import settings from '../../../../modules/settings/Settings';
14 17
 
15 18
 /**
16 19
  * Root application component.
@@ -23,7 +26,7 @@ export class App extends AbstractApp {
23 26
      *
24 27
      * @static
25 28
      */
26
-    static propTypes = AbstractApp.propTypes
29
+    static propTypes = AbstractApp.propTypes;
27 30
 
28 31
     /**
29 32
      * Initializes a new App instance.
@@ -44,28 +47,19 @@ export class App extends AbstractApp {
44 47
         // Bind event handlers so they are only bound once for every instance.
45 48
         this._onRouteEnter = this._onRouteEnter.bind(this);
46 49
         this._routerCreateElement = this._routerCreateElement.bind(this);
50
+        this._getRoute = this._getRoute.bind(this);
51
+        this._getRoutes = this._getRoutes.bind(this);
47 52
     }
48 53
 
49 54
     /**
50
-     * Temporarily, prevents the super from dispatching Redux actions until they
51
-     * are integrated into the Web App.
55
+     * Init translation from old app.
52 56
      *
53
-     * @returns {void}
57
+     * @inheritdoc
54 58
      */
55
-    componentWillMount() {
56
-        // FIXME Do not override the super once the dispatching of Redux actions
57
-        // is integrated into the Web App.
58
-    }
59
+    componentWillMount(...args) {
60
+        super.componentWillMount(...args);
59 61
 
60
-    /**
61
-     * Temporarily, prevents the super from dispatching Redux actions until they
62
-     * are integrated into the Web App.
63
-     *
64
-     * @returns {void}
65
-     */
66
-    componentWillUnmount() {
67
-        // FIXME Do not override the super once the dispatching of Redux actions
68
-        // is integrated into the Web App.
62
+        APP.translation.init(settings.getLanguage());
69 63
     }
70 64
 
71 65
     /**
@@ -75,19 +69,14 @@ export class App extends AbstractApp {
75 69
      * @returns {ReactElement}
76 70
      */
77 71
     render() {
78
-        const routes = RouteRegistry.getRoutes();
72
+
79 73
 
80 74
         return (
81 75
             <Provider store = { this.props.store }>
82 76
                 <Router
83 77
                     createElement = { this._routerCreateElement }
84 78
                     history = { this.history }>
85
-                    { routes.map(r =>
86
-                        <Route
87
-                            component = { r.component }
88
-                            key = { r.component }
89
-                            path = { r.path } />
90
-                    ) }
79
+                    { this._getRoutes() }
91 80
                 </Router>
92 81
             </Provider>
93 82
         );
@@ -114,6 +103,38 @@ export class App extends AbstractApp {
114 103
         return store.dispatch(push(path));
115 104
     }
116 105
 
106
+    /**
107
+     * Returns routes for application.
108
+     *
109
+     * @returns {Array}
110
+     * @private
111
+     */
112
+    _getRoutes() {
113
+        const routes = RouteRegistry.getRoutes();
114
+
115
+        return routes.map(this._getRoute);
116
+    }
117
+
118
+    /**
119
+     * Method returns route for React Router.
120
+     *
121
+     * @param {Object} route - Object that describes route.
122
+     * @returns {ReactElement}
123
+     * @private
124
+     */
125
+    _getRoute(route) {
126
+        const onEnter = route.onEnter || $.noop;
127
+        const handler = compose(this._onRouteEnter, onEnter);
128
+
129
+        return (
130
+            <Route
131
+                component = { route.component }
132
+                key = { route.component }
133
+                onEnter = { handler }
134
+                path = { route.path } />
135
+        );
136
+    }
137
+
117 138
     /**
118 139
      * Invoked by react-router to notify this App that a Route is about to be
119 140
      * rendered.
@@ -122,6 +143,7 @@ export class App extends AbstractApp {
122 143
      * @returns {void}
123 144
      */
124 145
     _onRouteEnter() {
146
+
125 147
         // XXX The following is mandatory. Otherwise, moving back & forward
126 148
         // through the browser's history could leave this App on the Conference
127 149
         // page without a room name.

react/features/base/connection/actions.js → react/features/base/connection/actions.native.js View File


+ 96
- 0
react/features/base/connection/actions.web.js View File

@@ -0,0 +1,96 @@
1
+/* global APP, JitsiMeetJS */
2
+
3
+import {
4
+    SET_DOMAIN
5
+} from './actionTypes';
6
+import './reducer';
7
+import UIEvents from '../../../../service/UI/UIEvents';
8
+
9
+const logger = require('jitsi-meet-logger').getLogger(__filename);
10
+const ConferenceEvents = JitsiMeetJS.events.conference;
11
+
12
+
13
+/**
14
+ * Opens new connection.
15
+ *
16
+ * @returns {Promise<JitsiConnection>}
17
+ */
18
+export function connect() {
19
+    return (dispatch, getState) => {
20
+        const state = getState();
21
+        const room = state['features/base/conference'].room;
22
+
23
+        // XXX For web based version we use conference initialization logic
24
+        // from the old app (at the moment of writing).
25
+        return APP.conference.init({ roomName: room }).then(() => {
26
+            if (APP.logCollector) {
27
+                // Start the LogCollector's periodic "store logs" task
28
+                APP.logCollector.start();
29
+                APP.logCollectorStarted = true;
30
+
31
+                // Make an attempt to flush in case a lot of logs have been
32
+                // cached, before the collector was started.
33
+                APP.logCollector.flush();
34
+
35
+                // This event listener will flush the logs, before
36
+                // the statistics module (CallStats) is stopped.
37
+                //
38
+                // NOTE The LogCollector is not stopped, because this event can
39
+                // be triggered multiple times during single conference
40
+                // (whenever statistics module is stopped). That includes
41
+                // the case when Jicofo terminates the single person left in the
42
+                // room. It will then restart the media session when someone
43
+                // eventually join the room which will start the stats again.
44
+                APP.conference.addConferenceListener(
45
+                    ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
46
+                    () => {
47
+                        if (APP.logCollector) {
48
+                            APP.logCollector.flush();
49
+                        }
50
+                    }
51
+                );
52
+            }
53
+
54
+            APP.UI.initConference();
55
+
56
+            APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
57
+                APP.translation.setLanguage(language);
58
+                APP.settings.setLanguage(language);
59
+            });
60
+
61
+            APP.keyboardshortcut.init();
62
+        })
63
+            .catch(err => {
64
+                APP.UI.hideRingOverLay();
65
+                APP.API.notifyConferenceLeft(APP.conference.roomName);
66
+                logger.error(err);
67
+            });
68
+    };
69
+}
70
+
71
+/**
72
+ * Closes connection.
73
+ *
74
+ * @returns {Function}
75
+ */
76
+export function disconnect() {
77
+    // XXX For web based version we use conference
78
+    // hanging up logic from the old app.
79
+    return () => APP.conference.hangup();
80
+}
81
+
82
+/**
83
+ * Sets connection domain.
84
+ *
85
+ * @param {string} domain - Domain name.
86
+ * @returns {{
87
+ *      type: SET_DOMAIN,
88
+ *      domain: string
89
+ *  }}
90
+ */
91
+export function setDomain(domain) {
92
+    return {
93
+        type: SET_DOMAIN,
94
+        domain
95
+    };
96
+}

react/features/base/lib-jitsi-meet/actions.js → react/features/base/lib-jitsi-meet/actions.native.js View File


+ 61
- 0
react/features/base/lib-jitsi-meet/actions.web.js View File

@@ -0,0 +1,61 @@
1
+import {
2
+    LIB_DISPOSED,
3
+    SET_CONFIG
4
+} from './actionTypes';
5
+import './middleware';
6
+import './reducer';
7
+
8
+/**
9
+ * Disposes lib-jitsi-meet.
10
+ *
11
+ * @returns {Function}
12
+ */
13
+export function disposeLib() {
14
+    // XXX We're wrapping it with Promise, because:
15
+    // a) to be better aligned with initLib() method, which is async.
16
+    // b) as currently there is no implementation for it in lib-jitsi-meet, and
17
+    // there is a big chance it will be async.
18
+    // TODO Currently, lib-jitsi-meet doesn't have any functionality to
19
+    // dispose itself.
20
+    return dispatch => {
21
+        dispatch({ type: LIB_DISPOSED });
22
+
23
+        return Promise.resolve();
24
+    };
25
+}
26
+
27
+/**
28
+ * Initializes lib-jitsi-meet with passed configuration.
29
+ *
30
+ * @returns {Function}
31
+ */
32
+export function initLib() {
33
+    return (dispatch, getState) => {
34
+        const config = getState()['features/base/lib-jitsi-meet'].config;
35
+
36
+        if (!config) {
37
+            throw new Error('Cannot initialize lib-jitsi-meet without config');
38
+        }
39
+
40
+        // XXX Temporary solution. Until conference.js hasn't been moved
41
+        // to the react app we shouldn't use JitsiMeetJS from react app.
42
+        return Promise.resolve();
43
+    };
44
+}
45
+
46
+/**
47
+ * Sets config.
48
+ *
49
+ * @param {Object} config - Config object accepted by JitsiMeetJS#init()
50
+ * method.
51
+ * @returns {{
52
+ *      type: SET_CONFIG,
53
+ *      config: Object
54
+ *  }}
55
+ */
56
+export function setConfig(config) {
57
+    return {
58
+        type: SET_CONFIG,
59
+        config
60
+    };
61
+}

react/features/base/lib-jitsi-meet/functions.js → react/features/base/lib-jitsi-meet/functions.native.js View File


+ 10
- 0
react/features/base/lib-jitsi-meet/functions.web.js View File

@@ -0,0 +1,10 @@
1
+/**
2
+ * Returns config.js file from global scope.
3
+ * We can't use version that's being used for native app
4
+ * because the old app uses config from global scope.
5
+ *
6
+ * @returns {Promise<Object>}
7
+ */
8
+export function loadConfig() {
9
+    return Promise.resolve(window.config);
10
+}

+ 46
- 2
react/features/conference/components/Conference.web.js View File

@@ -1,5 +1,12 @@
1
-/* global interfaceConfig */
1
+/* global APP, $, interfaceConfig */
2 2
 import React, { Component } from 'react';
3
+import { connect as reactReduxConnect } from 'react-redux';
4
+
5
+import {
6
+    connect,
7
+    disconnect
8
+} from '../../base/connection';
9
+
3 10
 
4 11
 /**
5 12
  * For legacy reasons, inline style for display none.
@@ -12,7 +19,42 @@ const DISPLAY_NONE_STYLE = {
12 19
 /**
13 20
  * Implements a React Component which renders initial conference layout
14 21
  */
15
-export default class Conference extends Component {
22
+class Conference extends Component {
23
+
24
+    /**
25
+     * Until we don't rewrite UI using react components
26
+     * we use UI.start from old app. Also method translates
27
+     * component right after it has been mounted.
28
+     *
29
+     * @inheritdoc
30
+     */
31
+    componentDidMount() {
32
+        APP.UI.start();
33
+
34
+        // XXX Temporary solution until we add React translation.
35
+        APP.translation.translateElement($('#videoconference_page'));
36
+
37
+        this.props.dispatch(connect());
38
+    }
39
+
40
+    /**
41
+     * Disconnect from the conference when component will be
42
+     * unmounted.
43
+     *
44
+     * @inheritdoc
45
+     */
46
+    componentWillUnmount() {
47
+        this.props.dispatch(disconnect());
48
+    }
49
+
50
+    /**
51
+     * Conference component's property types.
52
+     *
53
+     * @static
54
+     */
55
+    static propTypes = {
56
+        dispatch: React.PropTypes.func
57
+    };
16 58
 
17 59
     /**
18 60
      * Initializes Conference component instance.
@@ -214,3 +256,5 @@ export default class Conference extends Component {
214 256
         return null;
215 257
     }
216 258
 }
259
+
260
+export default reactReduxConnect()(Conference);

+ 41
- 8
react/features/welcome/components/WelcomePage.web.js View File

@@ -1,4 +1,4 @@
1
-/* global APP, interfaceConfig */
1
+/* global interfaceConfig, APP, $  */
2 2
 
3 3
 import React from 'react';
4 4
 import { connect } from 'react-redux';
@@ -52,6 +52,9 @@ class WelcomePage extends AbstractWelcomePage {
52 52
         if (this.state.generateRoomnames) {
53 53
             this._updateRoomname();
54 54
         }
55
+
56
+        // XXX Temporary solution until we add React translation.
57
+        APP.translation.translateElement($('#welcome_page'));
55 58
     }
56 59
 
57 60
     /**
@@ -61,12 +64,6 @@ class WelcomePage extends AbstractWelcomePage {
61 64
      * @returns {ReactElement|null}
62 65
      */
63 66
     render() {
64
-        // FIXME The rendering of Conference bellow is a very quick and dirty
65
-        // temporary fix for the following issue: when the WelcomePage is
66
-        // disabled, app.js expects Conference to be rendered already and only
67
-        // then it builds a room name but the App component expects the room
68
-        // name to be built already (by looking at the window's location) in
69
-        // order to choose between WelcomePage and Conference.
70 67
         return (
71 68
             <div>
72 69
                 <div id = 'welcome_page'>
@@ -77,7 +74,6 @@ class WelcomePage extends AbstractWelcomePage {
77 74
                         this._renderMain()
78 75
                     }
79 76
                 </div>
80
-                <Conference />
81 77
             </div>
82 78
         );
83 79
     }
@@ -359,6 +355,43 @@ class WelcomePage extends AbstractWelcomePage {
359 355
         return null;
360 356
     }
361 357
 
358
+    /**
359
+    * Handles updating roomname.
360
+    *
361
+    * @private
362
+    * @returns {void}
363
+    **/
364
+    _onUpdateRoomname() {
365
+        this._updateRoomname();
366
+    }
367
+
368
+    /**
369
+    * Event handler for changing room name input from web.
370
+    *
371
+    * @inheritdoc
372
+    * @override
373
+    * @protected
374
+    */
375
+    _onRoomChange() {
376
+        super._onRoomChange(this.roomNameInput.value);
377
+    }
378
+
379
+    /**
380
+    * Handles 'keydown' event and initiate joining the room if 'return' button
381
+    * was pressed.
382
+    *
383
+    * @param {Event} event - Key down event object.
384
+    * @returns {void}
385
+    * @private
386
+    */
387
+    _onKeyDown(event) {
388
+        const RETURN_BUTTON_CODE = 13;
389
+
390
+        if (event.keyCode === RETURN_BUTTON_CODE) {
391
+            this._onJoin();
392
+        }
393
+    }
394
+
362 395
     /**
363 396
      * Renders the main part of this WelcomePage.
364 397
      *

+ 22
- 2
react/features/welcome/route.js View File

@@ -1,11 +1,31 @@
1
+/* global APP */
1 2
 import { RouteRegistry } from '../base/navigator';
2
-
3
+import { generateRoomWithoutSeparator } from '../base/util';
3 4
 import { WelcomePage } from './components';
4 5
 
6
+
7
+/**
8
+ * Function that checks if welcome page is enabled and if it isn't
9
+ * redirects to randomly created conference.
10
+ *
11
+ * @param {Object} nextState - Next router state.
12
+ * @param {Function} replace - Function to redirect to another path.
13
+ * @returns {void}
14
+ */
15
+function onEnter(nextState, replace) {
16
+    if (!APP.settings.isWelcomePageEnabled()) {
17
+        const generatedRoomname = generateRoomWithoutSeparator();
18
+        const normalizedRoomname = generatedRoomname.toLowerCase();
19
+
20
+        replace(`/${normalizedRoomname}`);
21
+    }
22
+}
23
+
5 24
 /**
6 25
  * Register route for WelcomePage.
7 26
  */
8 27
 RouteRegistry.register({
9 28
     component: WelcomePage,
10
-    path: '/'
29
+    path: '/',
30
+    onEnter
11 31
 });

Loading…
Cancel
Save