Remove duplication, simplify, comply with coding style

This commit is contained in:
Lyubomir Marinov 2017-01-10 13:06:18 -06:00
parent b67994235e
commit 2f01746c55
13 changed files with 77 additions and 304 deletions

10
app.js
View File

@ -63,11 +63,11 @@ const APP = {
};
// TODO The execution of the mobile app starts from react/index.native.js.
// Similarly, the execution of the Web app should start from
// react/index.web.js for the sake of consistency and ease of understanding.
// Temporarily though because we are at the beginning of introducing React
// 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.
// Similarly, the execution of the Web app should start from react/index.web.js
// for the sake of consistency and ease of understanding. Temporarily though
// because we are at the beginning of introducing React 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');
module.exports = APP;

View File

@ -19,6 +19,16 @@ import {
} from './functions';
import './reducer';
/**
* Temporary solution. Should dispatch actions related to
* initial settings of the app like setting log levels,
* reading the config parameters from query string etc.
*
* @returns {Function}
*/
export function appInit() {
return () => init();
}
/**
* Triggers an in-app navigation to a different route. Allows navigation to be
@ -91,19 +101,6 @@ export function appNavigate(urlOrRoom) {
};
}
/**
* Temporary solution. Should dispatch actions related to
* initial settings of the app like setting log levels,
* reading the config parameters from query string etc.
*
* @returns {Function}
*/
export function appInit() {
return () => {
init();
};
}
/**
* Signals that a specific App will mount (in the terms of React).
*

View File

@ -1,158 +0,0 @@
import { setRoom } from '../base/conference';
import {
getDomain,
setDomain
} from '../base/connection';
import {
loadConfig,
setConfig
} from '../base/lib-jitsi-meet';
import {
APP_WILL_MOUNT,
APP_WILL_UNMOUNT
} from './actionTypes';
import {
_getRoomAndDomainFromUrlString,
_getRouteToRender
} from './functions';
import './reducer';
/**
* Triggers an in-app navigation to a different route. Allows navigation to be
* abstracted between the mobile and web versions.
*
* @param {(string|undefined)} urlOrRoom - The URL or room name to which to
* navigate.
* @returns {Function}
*/
export function appNavigate(urlOrRoom) {
return (dispatch, getState) => {
const oldDomain = getDomain(getState());
const { domain, room } = _getRoomAndDomainFromUrlString(urlOrRoom);
// TODO Kostiantyn Tsaregradskyi: We should probably detect if user is
// currently in a conference and ask her if she wants to close the
// current conference and start a new one with the new room name or
// domain.
if (typeof domain === 'undefined' || oldDomain === domain) {
// If both domain and room vars became undefined, that means we're
// actually dealing with just room name and not with URL.
dispatch(
_setRoomAndNavigate(
typeof room === 'undefined' && typeof domain === 'undefined'
? urlOrRoom
: room));
} else if (oldDomain !== domain) {
// Update domain without waiting for config to be loaded to prevent
// race conditions when we will start to load config multiple times.
dispatch(setDomain(domain));
// If domain has changed, we need to load the config of the new
// domain and set it, and only after that we can navigate to
// different route.
loadConfig(`https://${domain}`)
.then(
config => configLoaded(/* err */ undefined, config),
err => configLoaded(err, /* config */ undefined));
}
/**
* Notifies that an attempt to load the config(uration) of domain has
* completed.
*
* @param {string|undefined} err - If the loading has failed, the error
* detailing the cause of the failure.
* @param {Object|undefined} config - If the loading has succeeded, the
* loaded config(uration).
* @returns {void}
*/
function configLoaded(err, config) {
if (err) {
// XXX The failure could be, for example, because of a
// certificate-related error. In which case the connection will
// fail later in Strophe anyway even if we use the default
// config here.
// The function loadConfig will log the err.
return;
}
// We set room name only here to prevent race conditions on app
// start to not make app re-render conference page for two times.
dispatch(setRoom(room));
dispatch(setConfig(config));
_navigate(getState());
}
};
}
/**
* Signals that a specific App will mount (in the terms of React).
*
* @param {App} app - The App which will mount.
* @returns {{
* type: APP_WILL_MOUNT,
* app: App
* }}
*/
export function appWillMount(app) {
return {
type: APP_WILL_MOUNT,
app
};
}
/**
* Signals that a specific App will unmount (in the terms of React).
*
* @param {App} app - The App which will unmount.
* @returns {{
* type: APP_WILL_UNMOUNT,
* app: App
* }}
*/
export function appWillUnmount(app) {
return {
type: APP_WILL_UNMOUNT,
app
};
}
/**
* Navigates to route corresponding to current room name.
*
* @param {Object} state - Redux state.
* @private
* @returns {void}
*/
function _navigate(state) {
const app = state['features/app'].app;
const routeToRender = _getRouteToRender(state);
app._navigate(routeToRender);
}
/**
* Sets room and navigates to new route if needed.
*
* @param {string} newRoom - New room name.
* @private
* @returns {Function}
*/
function _setRoomAndNavigate(newRoom) {
return (dispatch, getState) => {
const oldRoom = getState()['features/base/conference'].room;
dispatch(setRoom(newRoom));
const state = getState();
const room = state['features/base/conference'].room;
if (room !== oldRoom) {
_navigate(state);
}
};
}

View File

@ -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

View File

@ -1,20 +1,19 @@
/* global $ */
import React from 'react';
import { Provider } from 'react-redux';
import { compose } from 'redux';
import {
browserHistory,
Route,
Router
} from 'react-router';
import { push, syncHistoryWithStore } from 'react-router-redux';
import { compose } from 'redux';
import { getDomain } from '../../base/connection';
import { RouteRegistry } from '../../base/navigator';
import { AbstractApp } from './AbstractApp';
import { appInit } from '../actions';
import { AbstractApp } from './AbstractApp';
/**
* Root application component.
@ -27,7 +26,7 @@ export class App extends AbstractApp {
*
* @static
*/
static propTypes = AbstractApp.propTypes;
static propTypes = AbstractApp.propTypes
/**
* Initializes a new App instance.
@ -46,10 +45,10 @@ export class App extends AbstractApp {
this.history = syncHistoryWithStore(browserHistory, props.store);
// 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);
this._onRouteEnter = this._onRouteEnter.bind(this);
this._routerCreateElement = this._routerCreateElement.bind(this);
}
/**
@ -59,6 +58,7 @@ export class App extends AbstractApp {
*/
componentWillMount(...args) {
super.componentWillMount(...args);
this.props.store.dispatch(appInit());
}
@ -69,7 +69,6 @@ export class App extends AbstractApp {
* @returns {ReactElement}
*/
render() {
return (
<Provider store = { this.props.store }>
<Router
@ -81,6 +80,38 @@ export class App extends AbstractApp {
);
}
/**
* 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 } />
);
}
/**
* Returns routes for application.
*
* @returns {Array}
* @private
*/
_getRoutes() {
const routes = RouteRegistry.getRoutes();
return routes.map(this._getRoute);
}
/**
* Navigates to a specific Route (via platform-specific means).
*
@ -102,38 +133,6 @@ 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.
@ -142,7 +141,6 @@ 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.

View File

@ -1,3 +1,5 @@
import React from 'react';
import JitsiMeetJS from './';
import {
LIB_DISPOSED,
@ -40,6 +42,12 @@ export function initLib() {
throw new Error('Cannot initialize lib-jitsi-meet without config');
}
if (!React.View) {
// XXX Temporarily until conference.js is moved to the React app we
// shouldn't use JitsiMeetJS from the React app.
return Promise.resolve();
}
return JitsiMeetJS.init(config)
.then(() => dispatch({ type: LIB_INITIALIZED }))
.catch(error => {

View File

@ -1,61 +0,0 @@
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
};
}

View File

@ -1,3 +1,5 @@
import React from 'react';
import { loadScript } from '../../base/util';
/**
@ -8,6 +10,13 @@ import { loadScript } from '../../base/util';
* @returns {Promise<Object>}
*/
export function loadConfig(host, path = '/config.js') {
if (!React.View) {
// Returns config.js file from global scope. We can't use the version
// that's being used for the React Native app because the old/current
// Web app uses config from the global scope.
return Promise.resolve(window.config);
}
return loadScript(new URL(path, host).toString())
.then(() => {
const config = window.config;

View File

@ -1,10 +0,0 @@
/**
* 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);
}

View File

@ -1,4 +1,4 @@
/* global APP, $, interfaceConfig */
/* global $, APP, interfaceConfig */
import React, { Component } from 'react';
import { connect as reactReduxConnect } from 'react-redux';

View File

@ -8,10 +8,10 @@ import { obtainConfigAndInit } from './functions';
*/
RouteRegistry.register({
component: Conference,
path: '/:room',
onEnter: () => {
// XXX: If config or jwt are set by hash or query parameters
// Getting raw URL before stripping it.
obtainConfigAndInit();
}
},
path: '/:room'
});

View File

@ -1,4 +1,4 @@
/* global interfaceConfig, APP, $ */
/* global $, APP, interfaceConfig */
import React from 'react';
import { connect } from 'react-redux';
@ -340,16 +340,6 @@ class WelcomePage extends AbstractWelcomePage {
return null;
}
/**
* Handles updating roomname.
*
* @private
* @returns {void}
*/
_onUpdateRoomname() {
this._updateRoomname();
}
/**
* Renders the main part of this WelcomePage.
*

View File

@ -26,6 +26,6 @@ function onEnter(nextState, replace) {
*/
RouteRegistry.register({
component: WelcomePage,
path: '/',
onEnter
onEnter,
path: '/'
});