moved app initialization to react app
This commit is contained in:
parent
fd6c91715f
commit
c570b80d7b
108
app.js
108
app.js
|
@ -1,4 +1,4 @@
|
|||
/* global $, config, getRoomName, loggingConfig, JitsiMeetJS */
|
||||
/* global $, config, loggingConfig, JitsiMeetJS */
|
||||
/* application specific logic */
|
||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||
|
||||
|
@ -23,9 +23,6 @@ const LogCollector = Logger.LogCollector;
|
|||
import JitsiMeetLogStorage from "./modules/util/JitsiMeetLogStorage";
|
||||
|
||||
import URLProcessor from "./modules/config/URLProcessor";
|
||||
import {
|
||||
generateRoomWithoutSeparator
|
||||
} from './react/features/base/util/roomnameGenerator';
|
||||
|
||||
import UI from "./modules/UI/UI";
|
||||
import settings from "./modules/settings/Settings";
|
||||
|
@ -33,59 +30,9 @@ import conference from './conference';
|
|||
import ConferenceUrl from './modules/URL/ConferenceUrl';
|
||||
import API from './modules/API/API';
|
||||
|
||||
import UIEvents from './service/UI/UIEvents';
|
||||
import getTokenData from "./modules/tokendata/TokenData";
|
||||
import translation from "./modules/translation/translation";
|
||||
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
/**
|
||||
* Tries to push history state with the following parameters:
|
||||
* 'VideoChat', `Room: ${roomName}`, URL. If fail, prints the error and returns
|
||||
* it.
|
||||
*/
|
||||
function pushHistoryState(roomName, URL) {
|
||||
try {
|
||||
window.history.pushState(
|
||||
'VideoChat', `Room: ${roomName}`, URL
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warn("Push history state failed with parameters:",
|
||||
'VideoChat', `Room: ${roomName}`, URL, e);
|
||||
return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces current history state(replaces the URL displayed by the browser).
|
||||
* @param {string} newUrl the URL string which is to be displayed by the browser
|
||||
* to the user.
|
||||
*/
|
||||
function replaceHistoryState (newUrl) {
|
||||
if (window.history
|
||||
&& typeof window.history.replaceState === 'function') {
|
||||
window.history.replaceState({}, document.title, newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns the room name.
|
||||
*/
|
||||
function buildRoomName () {
|
||||
let roomName = getRoomName();
|
||||
|
||||
if(!roomName) {
|
||||
let word = generateRoomWithoutSeparator();
|
||||
roomName = word.toLowerCase();
|
||||
let historyURL = window.location.href + word;
|
||||
//Trying to push state with current URL + roomName
|
||||
pushHistoryState(word, historyURL);
|
||||
}
|
||||
|
||||
return roomName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the logging levels.
|
||||
* @private
|
||||
|
@ -191,8 +138,6 @@ function init() {
|
|||
setTokenData();
|
||||
// Initialize the conference URL handler
|
||||
APP.ConferenceUrl = new ConferenceUrl(window.location);
|
||||
// Clean up the URL displayed by the browser
|
||||
replaceHistoryState(APP.ConferenceUrl.getInviteUrl());
|
||||
|
||||
// TODO The execution of the mobile app starts from react/index.native.js.
|
||||
// Similarly, the execution of the Web app should start from
|
||||
|
@ -201,54 +146,6 @@ function init() {
|
|||
// into the Web app, allow the execution of the Web app to start from app.js
|
||||
// in order to reduce the complexity of the beginning step.
|
||||
require('./react');
|
||||
|
||||
const isUIReady = APP.UI.start();
|
||||
if (isUIReady) {
|
||||
APP.conference.init({roomName: buildRoomName()}).then(() => {
|
||||
|
||||
if (APP.logCollector) {
|
||||
// Start the LogCollector's periodic "store logs" task only if
|
||||
// we're in the conference and not on the welcome page. This is
|
||||
// determined by the value of "isUIReady" const above.
|
||||
APP.logCollector.start();
|
||||
APP.logCollectorStarted = true;
|
||||
// Make an attempt to flush in case a lot of logs have been
|
||||
// cached, before the collector was started.
|
||||
APP.logCollector.flush();
|
||||
|
||||
// This event listener will flush the logs, before
|
||||
// the statistics module (CallStats) is stopped.
|
||||
//
|
||||
// NOTE The LogCollector is not stopped, because this event can
|
||||
// be triggered multiple times during single conference
|
||||
// (whenever statistics module is stopped). That includes
|
||||
// the case when Jicofo terminates the single person left in the
|
||||
// room. It will then restart the media session when someone
|
||||
// eventually join the room which will start the stats again.
|
||||
APP.conference.addConferenceListener(
|
||||
ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
|
||||
() => {
|
||||
if (APP.logCollector) {
|
||||
APP.logCollector.flush();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
|
||||
APP.translation.setLanguage(language);
|
||||
APP.settings.setLanguage(language);
|
||||
});
|
||||
|
||||
APP.keyboardshortcut.init();
|
||||
}).catch(err => {
|
||||
APP.UI.hideRingOverLay();
|
||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -295,9 +192,6 @@ $(document).ready(function () {
|
|||
URLProcessor.setConfigParametersFromUrl();
|
||||
|
||||
APP.init();
|
||||
|
||||
APP.translation.init(settings.getLanguage());
|
||||
|
||||
APP.API.init(APP.tokenData.externalAPISettings);
|
||||
|
||||
obtainConfigAndInit();
|
||||
|
|
|
@ -396,20 +396,6 @@ UI.getSharedVideoManager = function () {
|
|||
*/
|
||||
UI.start = function () {
|
||||
document.title = interfaceConfig.APP_NAME;
|
||||
var setupWelcomePage = null;
|
||||
if(config.enableWelcomePage && window.location.pathname == "/" &&
|
||||
Settings.isWelcomePageEnabled()) {
|
||||
$("#videoconference_page").hide();
|
||||
if (!setupWelcomePage)
|
||||
setupWelcomePage = require("./welcome_page/WelcomePage");
|
||||
setupWelcomePage();
|
||||
|
||||
// Return false to indicate that the UI hasn't been fully started and
|
||||
// conference ready. We're still waiting for input from the user.
|
||||
return false;
|
||||
}
|
||||
|
||||
$("#welcome_page").hide();
|
||||
|
||||
// Set the defaults for prompt dialogs.
|
||||
$.prompt.setDefaults({persistent: false});
|
||||
|
|
|
@ -42,7 +42,7 @@ export class AbstractApp extends Component {
|
|||
* The URL, if any, with which the app was launched.
|
||||
*/
|
||||
url: React.PropTypes.string
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Init lib-jitsi-meet and create local participant when component is going
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* global APP, $ */
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { compose } from 'redux';
|
||||
import {
|
||||
browserHistory,
|
||||
Route,
|
||||
|
@ -11,6 +13,7 @@ import { getDomain } from '../../base/connection';
|
|||
import { RouteRegistry } from '../../base/navigator';
|
||||
|
||||
import { AbstractApp } from './AbstractApp';
|
||||
import settings from '../../../../modules/settings/Settings';
|
||||
|
||||
/**
|
||||
* Root application component.
|
||||
|
@ -23,7 +26,7 @@ export class App extends AbstractApp {
|
|||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = AbstractApp.propTypes
|
||||
static propTypes = AbstractApp.propTypes;
|
||||
|
||||
/**
|
||||
* Initializes a new App instance.
|
||||
|
@ -44,28 +47,19 @@ export class App extends AbstractApp {
|
|||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onRouteEnter = this._onRouteEnter.bind(this);
|
||||
this._routerCreateElement = this._routerCreateElement.bind(this);
|
||||
this._getRoute = this._getRoute.bind(this);
|
||||
this._getRoutes = this._getRoutes.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily, prevents the super from dispatching Redux actions until they
|
||||
* are integrated into the Web App.
|
||||
* Init translation from old app.
|
||||
*
|
||||
* @returns {void}
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillMount() {
|
||||
// FIXME Do not override the super once the dispatching of Redux actions
|
||||
// is integrated into the Web App.
|
||||
}
|
||||
componentWillMount(...args) {
|
||||
super.componentWillMount(...args);
|
||||
|
||||
/**
|
||||
* Temporarily, prevents the super from dispatching Redux actions until they
|
||||
* are integrated into the Web App.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
// FIXME Do not override the super once the dispatching of Redux actions
|
||||
// is integrated into the Web App.
|
||||
APP.translation.init(settings.getLanguage());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,19 +69,14 @@ export class App extends AbstractApp {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const routes = RouteRegistry.getRoutes();
|
||||
|
||||
|
||||
return (
|
||||
<Provider store = { this.props.store }>
|
||||
<Router
|
||||
createElement = { this._routerCreateElement }
|
||||
history = { this.history }>
|
||||
{ routes.map(r =>
|
||||
<Route
|
||||
component = { r.component }
|
||||
key = { r.component }
|
||||
path = { r.path } />
|
||||
) }
|
||||
{ this._getRoutes() }
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
|
@ -114,6 +103,38 @@ export class App extends AbstractApp {
|
|||
return store.dispatch(push(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns routes for application.
|
||||
*
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
_getRoutes() {
|
||||
const routes = RouteRegistry.getRoutes();
|
||||
|
||||
return routes.map(this._getRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method returns route for React Router.
|
||||
*
|
||||
* @param {Object} route - Object that describes route.
|
||||
* @returns {ReactElement}
|
||||
* @private
|
||||
*/
|
||||
_getRoute(route) {
|
||||
const onEnter = route.onEnter || $.noop;
|
||||
const handler = compose(this._onRouteEnter, onEnter);
|
||||
|
||||
return (
|
||||
<Route
|
||||
component = { route.component }
|
||||
key = { route.component }
|
||||
onEnter = { handler }
|
||||
path = { route.path } />
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by react-router to notify this App that a Route is about to be
|
||||
* rendered.
|
||||
|
@ -122,6 +143,7 @@ export class App extends AbstractApp {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onRouteEnter() {
|
||||
|
||||
// XXX The following is mandatory. Otherwise, moving back & forward
|
||||
// through the browser's history could leave this App on the Conference
|
||||
// page without a room name.
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* global APP, JitsiMeetJS */
|
||||
|
||||
import {
|
||||
SET_DOMAIN
|
||||
} from './actionTypes';
|
||||
import './reducer';
|
||||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
const ConferenceEvents = JitsiMeetJS.events.conference;
|
||||
|
||||
|
||||
/**
|
||||
* Opens new connection.
|
||||
*
|
||||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
export function connect() {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const room = state['features/base/conference'].room;
|
||||
|
||||
// XXX For web based version we use conference initialization logic
|
||||
// from the old app (at the moment of writing).
|
||||
return APP.conference.init({ roomName: room }).then(() => {
|
||||
if (APP.logCollector) {
|
||||
// Start the LogCollector's periodic "store logs" task
|
||||
APP.logCollector.start();
|
||||
APP.logCollectorStarted = true;
|
||||
|
||||
// Make an attempt to flush in case a lot of logs have been
|
||||
// cached, before the collector was started.
|
||||
APP.logCollector.flush();
|
||||
|
||||
// This event listener will flush the logs, before
|
||||
// the statistics module (CallStats) is stopped.
|
||||
//
|
||||
// NOTE The LogCollector is not stopped, because this event can
|
||||
// be triggered multiple times during single conference
|
||||
// (whenever statistics module is stopped). That includes
|
||||
// the case when Jicofo terminates the single person left in the
|
||||
// room. It will then restart the media session when someone
|
||||
// eventually join the room which will start the stats again.
|
||||
APP.conference.addConferenceListener(
|
||||
ConferenceEvents.BEFORE_STATISTICS_DISPOSED,
|
||||
() => {
|
||||
if (APP.logCollector) {
|
||||
APP.logCollector.flush();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
APP.UI.initConference();
|
||||
|
||||
APP.UI.addListener(UIEvents.LANG_CHANGED, language => {
|
||||
APP.translation.setLanguage(language);
|
||||
APP.settings.setLanguage(language);
|
||||
});
|
||||
|
||||
APP.keyboardshortcut.init();
|
||||
})
|
||||
.catch(err => {
|
||||
APP.UI.hideRingOverLay();
|
||||
APP.API.notifyConferenceLeft(APP.conference.roomName);
|
||||
logger.error(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes connection.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function disconnect() {
|
||||
// XXX For web based version we use conference
|
||||
// hanging up logic from the old app.
|
||||
return () => APP.conference.hangup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets connection domain.
|
||||
*
|
||||
* @param {string} domain - Domain name.
|
||||
* @returns {{
|
||||
* type: SET_DOMAIN,
|
||||
* domain: string
|
||||
* }}
|
||||
*/
|
||||
export function setDomain(domain) {
|
||||
return {
|
||||
type: SET_DOMAIN,
|
||||
domain
|
||||
};
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import {
|
||||
LIB_DISPOSED,
|
||||
SET_CONFIG
|
||||
} from './actionTypes';
|
||||
import './middleware';
|
||||
import './reducer';
|
||||
|
||||
/**
|
||||
* Disposes lib-jitsi-meet.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function disposeLib() {
|
||||
// XXX We're wrapping it with Promise, because:
|
||||
// a) to be better aligned with initLib() method, which is async.
|
||||
// b) as currently there is no implementation for it in lib-jitsi-meet, and
|
||||
// there is a big chance it will be async.
|
||||
// TODO Currently, lib-jitsi-meet doesn't have any functionality to
|
||||
// dispose itself.
|
||||
return dispatch => {
|
||||
dispatch({ type: LIB_DISPOSED });
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes lib-jitsi-meet with passed configuration.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function initLib() {
|
||||
return (dispatch, getState) => {
|
||||
const config = getState()['features/base/lib-jitsi-meet'].config;
|
||||
|
||||
if (!config) {
|
||||
throw new Error('Cannot initialize lib-jitsi-meet without config');
|
||||
}
|
||||
|
||||
// XXX Temporary solution. Until conference.js hasn't been moved
|
||||
// to the react app we shouldn't use JitsiMeetJS from react app.
|
||||
return Promise.resolve();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets config.
|
||||
*
|
||||
* @param {Object} config - Config object accepted by JitsiMeetJS#init()
|
||||
* method.
|
||||
* @returns {{
|
||||
* type: SET_CONFIG,
|
||||
* config: Object
|
||||
* }}
|
||||
*/
|
||||
export function setConfig(config) {
|
||||
return {
|
||||
type: SET_CONFIG,
|
||||
config
|
||||
};
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Returns config.js file from global scope.
|
||||
* We can't use version that's being used for native app
|
||||
* because the old app uses config from global scope.
|
||||
*
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
export function loadConfig() {
|
||||
return Promise.resolve(window.config);
|
||||
}
|
|
@ -1,5 +1,12 @@
|
|||
/* global interfaceConfig */
|
||||
/* global APP, $, interfaceConfig */
|
||||
import React, { Component } from 'react';
|
||||
import { connect as reactReduxConnect } from 'react-redux';
|
||||
|
||||
import {
|
||||
connect,
|
||||
disconnect
|
||||
} from '../../base/connection';
|
||||
|
||||
|
||||
/**
|
||||
* For legacy reasons, inline style for display none.
|
||||
|
@ -12,7 +19,42 @@ const DISPLAY_NONE_STYLE = {
|
|||
/**
|
||||
* Implements a React Component which renders initial conference layout
|
||||
*/
|
||||
export default class Conference extends Component {
|
||||
class Conference extends Component {
|
||||
|
||||
/**
|
||||
* Until we don't rewrite UI using react components
|
||||
* we use UI.start from old app. Also method translates
|
||||
* component right after it has been mounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentDidMount() {
|
||||
APP.UI.start();
|
||||
|
||||
// XXX Temporary solution until we add React translation.
|
||||
APP.translation.translateElement($('#videoconference_page'));
|
||||
|
||||
this.props.dispatch(connect());
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the conference when component will be
|
||||
* unmounted.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.props.dispatch(disconnect());
|
||||
}
|
||||
|
||||
/**
|
||||
* Conference component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
dispatch: React.PropTypes.func
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes Conference component instance.
|
||||
|
@ -214,3 +256,5 @@ export default class Conference extends Component {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default reactReduxConnect()(Conference);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global APP, interfaceConfig */
|
||||
/* global interfaceConfig, APP, $ */
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
@ -52,6 +52,9 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
if (this.state.generateRoomnames) {
|
||||
this._updateRoomname();
|
||||
}
|
||||
|
||||
// XXX Temporary solution until we add React translation.
|
||||
APP.translation.translateElement($('#welcome_page'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,12 +64,6 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
* @returns {ReactElement|null}
|
||||
*/
|
||||
render() {
|
||||
// FIXME The rendering of Conference bellow is a very quick and dirty
|
||||
// temporary fix for the following issue: when the WelcomePage is
|
||||
// disabled, app.js expects Conference to be rendered already and only
|
||||
// then it builds a room name but the App component expects the room
|
||||
// name to be built already (by looking at the window's location) in
|
||||
// order to choose between WelcomePage and Conference.
|
||||
return (
|
||||
<div>
|
||||
<div id = 'welcome_page'>
|
||||
|
@ -77,7 +74,6 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
this._renderMain()
|
||||
}
|
||||
</div>
|
||||
<Conference />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -359,6 +355,43 @@ class WelcomePage extends AbstractWelcomePage {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles updating roomname.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
**/
|
||||
_onUpdateRoomname() {
|
||||
this._updateRoomname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for changing room name input from web.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
_onRoomChange() {
|
||||
super._onRoomChange(this.roomNameInput.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles 'keydown' event and initiate joining the room if 'return' button
|
||||
* was pressed.
|
||||
*
|
||||
* @param {Event} event - Key down event object.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
_onKeyDown(event) {
|
||||
const RETURN_BUTTON_CODE = 13;
|
||||
|
||||
if (event.keyCode === RETURN_BUTTON_CODE) {
|
||||
this._onJoin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the main part of this WelcomePage.
|
||||
*
|
||||
|
|
|
@ -1,11 +1,31 @@
|
|||
/* global APP */
|
||||
import { RouteRegistry } from '../base/navigator';
|
||||
|
||||
import { generateRoomWithoutSeparator } from '../base/util';
|
||||
import { WelcomePage } from './components';
|
||||
|
||||
|
||||
/**
|
||||
* Function that checks if welcome page is enabled and if it isn't
|
||||
* redirects to randomly created conference.
|
||||
*
|
||||
* @param {Object} nextState - Next router state.
|
||||
* @param {Function} replace - Function to redirect to another path.
|
||||
* @returns {void}
|
||||
*/
|
||||
function onEnter(nextState, replace) {
|
||||
if (!APP.settings.isWelcomePageEnabled()) {
|
||||
const generatedRoomname = generateRoomWithoutSeparator();
|
||||
const normalizedRoomname = generatedRoomname.toLowerCase();
|
||||
|
||||
replace(`/${normalizedRoomname}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register route for WelcomePage.
|
||||
*/
|
||||
RouteRegistry.register({
|
||||
component: WelcomePage,
|
||||
path: '/'
|
||||
path: '/',
|
||||
onEnter
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue