Ver código fonte

Split React components out of index.html

master
Ilya Daynatovich 8 anos atrás
pai
commit
c3428e8213

+ 9
- 0
app.js Ver arquivo

@@ -192,6 +192,15 @@ $(document).ready(function () {
192 192
     console.log("(TIME) document ready:\t", now);
193 193
 
194 194
     URLProcessor.setConfigParametersFromUrl();
195
+
196
+    // TODO The execution of the mobile app starts from react/index.native.js.
197
+    // Similarly, the execution of the Web app should start from
198
+    // react/index.web.js for the sake of consistency and ease of understanding.
199
+    // Temporarily though because we are at the beginning of introducing React
200
+    // into the Web app, allow the execution of the Web app to start from app.js
201
+    // in order to reduce the complexity of the beginning step.
202
+    require('./react');
203
+
195 204
     APP.init();
196 205
 
197 206
     APP.translation.init(settings.getLanguage());

+ 2
- 136
index.html Ver arquivo

@@ -34,7 +34,7 @@
34 34
                 window.removeEventListener(
35 35
                     'error', loadErrHandler, true /* capture phase */);
36 36
             }
37
-        }
37
+        };
38 38
         window.addEventListener(
39 39
             'error', loadErrHandler, true /* capture phase type of listener */);
40 40
     </script>
@@ -50,141 +50,7 @@
50 50
     <!--#include virtual="plugin.head.html" -->
51 51
   </head>
52 52
   <body>
53
-    <div id="welcome_page">
54
-        <div id="welcome_page_header">
55
-            <a target="_new">
56
-                <div class="watermark leftwatermark"></div>
57
-            </a>
58
-            <a target="_new">
59
-                <div class="watermark rightwatermark"></div>
60
-            </a>
61
-            <a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
62
-
63
-            <div id="enter_room_container">
64
-                <div id="enter_room_form" >
65
-                    <div id="domain_name"></div>
66
-                    <div id="enter_room">
67
-                        <input id="enter_room_field" type="text" autofocus/>
68
-                        <div class="icon-reload" id="reload_roomname"></div>
69
-                        <input id="enter_room_button" type="button" data-i18n="[value]welcomepage.go" value="GO" />
70
-
71
-                    </div>
72
-                </div>
73
-            </div>
74
-            <div id="brand_header"></div>
75
-            <input type='checkbox' name='checkbox' id="disable_welcome"/>
76
-            <label for="disable_welcome" class="disable_welcome_position" data-i18n="welcomepage.disable"></label>
77
-            <div id="header_text">
78
-                <!--#include virtual="plugin.header.text.html" -->
79
-            </div>
80
-        </div>
81
-        <div id="welcome_page_main">
82
-            <div id="features">
83
-                <div class="feature_row">
84
-                    <div class="feature_holder">
85
-                        <div class="feature_icon" data-i18n="welcomepage.feature1.title" ></div>
86
-                        <div class="feature_description" data-i18n="welcomepage.feature1.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
87
-                        </div>
88
-                    </div>
89
-                    <div class="feature_holder">
90
-                        <div class="feature_icon" data-i18n="welcomepage.feature2.title" ></div>
91
-                        <div class="feature_description" data-i18n="welcomepage.feature2.content">
92
-                        </div>
93
-                    </div>
94
-                    <div class="feature_holder">
95
-                        <div class="feature_icon" data-i18n="welcomepage.feature3.title" ></div>
96
-                        <div class="feature_description" data-i18n="welcomepage.feature3.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
97
-                        </div>
98
-                    </div>
99
-                    <div class="feature_holder">
100
-                        <div class="feature_icon" data-i18n="welcomepage.feature4.title" ></div>
101
-                        <div class="feature_description" data-i18n="welcomepage.feature4.content">
102
-                        </div>
103
-                    </div>
104
-                </div>
105
-                <div class="feature_row">
106
-                    <div class="feature_holder">
107
-                            <div class="feature_icon" data-i18n="welcomepage.feature5.title" ></div>
108
-                            <div class="feature_description" data-i18n="welcomepage.feature5.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
109
-                            </div>
110
-                    </div>
111
-                    <div class="feature_holder">
112
-                            <div class="feature_icon" data-i18n="welcomepage.feature6.title" ></div>
113
-                            <div class="feature_description" data-i18n="welcomepage.feature6.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
114
-                            </div>
115
-                    </div>
116
-                    <div class="feature_holder">
117
-                            <div class="feature_icon" data-i18n="welcomepage.feature7.title" ></div>
118
-                            <div class="feature_description" data-i18n="welcomepage.feature7.content" data-i18n-options='{ "postProcess": "resolveAppName" }'></div>
119
-                    </div>
120
-                    <div class="feature_holder">
121
-                            <div class="feature_icon" data-i18n="welcomepage.feature8.title" ></div>
122
-                            <div class="feature_description" data-i18n="welcomepage.feature8.content"></div>
123
-                    </div>
124
-                </div>
125
-            </div>
126
-        </div>
127
-        <!--#include virtual="plugin.welcomepage.footer.html" -->
128
-    </div>
129
-    <div id="videoconference_page">
130
-        <div id="mainToolbarContainer">
131
-                <div id="notice" class="notice" style="display: none">
132
-                    <span id="noticeText" class="noticeText"></span>
133
-                </div>
134
-                <div id="mainToolbar" class="toolbar"></div>
135
-        </div>
136
-        <div id="subject" class="hide"></div>
137
-
138
-        <div id="extendedToolbar" class="toolbar">
139
-            <div id="extendedToolbarButtons"></div>
140
-
141
-            <a class="button icon-feedback" id="feedbackButton"></a>
142
-
143
-            <div id="sideToolbarContainer"></div>
144
-        </div>
145
-        <div id="videospace">
146
-            <div id="largeVideoContainer" class="videocontainer">
147
-                <div id="sharedVideo"><div id="sharedVideoIFrame"></div></div>
148
-                <div id="etherpad"></div>
149
-                <a target="_new"><div class="watermark leftwatermark"></div></a>
150
-                <a target="_new"><div class="watermark rightwatermark"></div></a>
151
-                <a class="poweredby" href="http://jitsi.org" target="_new">
152
-                    <span data-i18n="poweredby"></span> jitsi.org
153
-                </a>
154
-                <div id="dominantSpeaker">
155
-                    <div class="dynamic-shadow"></div>
156
-                    <img id="dominantSpeakerAvatar" src=""/>
157
-                </div>
158
-                <span id="remoteConnectionMessage"></span>
159
-                <div id="largeVideoWrapper">
160
-                    <video id="largeVideo" muted="true" autoplay></video>
161
-                </div>
162
-                <span id="localConnectionMessage"></span>
163
-                <span id="videoResolutionLabel" class="video-state-indicator moveToCorner">HD</span>
164
-                <span id="recordingLabel" class="video-state-indicator centeredVideoLabel">
165
-                    <span id="recordingLabelText"></span>
166
-                    <img id="recordingSpinner" class="recordingSpinner" src="images/spin.svg"></img>
167
-                </span>
168
-            </div>
169
-            <div class="filmstrip">
170
-                <div class="filmstrip__videos" id="remoteVideos">
171
-                    <span id="localVideoContainer" class="videocontainer">
172
-                        <div class="videocontainer__background"></div>
173
-                        <span id="localVideoWrapper">
174
-                            <!--<video id="localVideo" autoplay muted></video> - is now per stream generated -->
175
-                        </span>
176
-                        <audio id="localAudio" autoplay muted></audio>
177
-                        <div class="videocontainer__toolbar"></div>
178
-                        <div class="videocontainer__toptoolbar"></div>
179
-                        <div class="videocontainer__hoverOverlay"></div>
180
-                    </span>
181
-                    <audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
182
-                    <audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
183
-                </div>
184
-            </div>
185
-
186
-        </div>
187
-    </div>
53
+    <div id="react"></div>
188 54
     <div id="keyboard-shortcuts" class="keyboard-shortcuts" style="display:none;">
189 55
         <div class="content">
190 56
             <ul id="keyboard-shortcuts-list" class="shortcuts-list">

+ 3
- 1
package.json Ver arquivo

@@ -39,7 +39,9 @@
39 39
     "react-native": "0.37.0",
40 40
     "react-native-vector-icons": "^2.0.3",
41 41
     "react-native-webrtc": "jitsi/react-native-webrtc",
42
-    "react-redux": "^4.4.5",
42
+    "react-redux": "^4.4.6",
43
+    "react-router": "^3.0.0",
44
+    "react-router-redux": "^4.0.7",
43 45
     "redux": "^3.5.2",
44 46
     "redux-thunk": "^2.1.0",
45 47
     "retry": "0.6.1",

+ 157
- 0
react/features/app/components/App.web.js Ver arquivo

@@ -0,0 +1,157 @@
1
+import React from 'react';
2
+import { Provider } from 'react-redux';
3
+import {
4
+    browserHistory,
5
+    Route,
6
+    Router
7
+} from 'react-router';
8
+import { push, syncHistoryWithStore } from 'react-router-redux';
9
+
10
+import { getDomain } from '../../base/connection';
11
+import { RouteRegistry } from '../../base/navigator';
12
+
13
+import { AbstractApp } from './AbstractApp';
14
+
15
+/**
16
+ * Root application component.
17
+ *
18
+ * @extends AbstractApp
19
+ */
20
+export class App extends AbstractApp {
21
+    /**
22
+     * Initializes a new App instance.
23
+     *
24
+     * @param {Object} props - The read-only React Component props with which
25
+     * the new instance is to be initialized.
26
+     */
27
+    constructor(props) {
28
+        super(props);
29
+
30
+        /**
31
+         * Create an enhanced history that syncs navigation events with the
32
+         * store.
33
+         * @link https://github.com/reactjs/react-router-redux#how-it-works
34
+         */
35
+        this.history = syncHistoryWithStore(browserHistory, props.store);
36
+
37
+        // Bind event handlers so they are only bound once for every instance.
38
+        this._onRouteEnter = this._onRouteEnter.bind(this);
39
+        this._routerCreateElement = this._routerCreateElement.bind(this);
40
+    }
41
+
42
+    /**
43
+     * Temporarily, prevents the super from dispatching Redux actions until they
44
+     * are integrated into the Web App.
45
+     *
46
+     * @returns {void}
47
+     */
48
+    componentWillMount() {
49
+        // FIXME Do not override the super once the dispatching of Redux actions
50
+        // is integrated into the Web App.
51
+    }
52
+
53
+    /**
54
+     * Temporarily, prevents the super from dispatching Redux actions until they
55
+     * are integrated into the Web App.
56
+     *
57
+     * @returns {void}
58
+     */
59
+    componentWillUnmount() {
60
+        // FIXME Do not override the super once the dispatching of Redux actions
61
+        // is integrated into the Web App.
62
+    }
63
+
64
+    /**
65
+     * Implements React's {@link Component#render()}.
66
+     *
67
+     * @inheritdoc
68
+     * @returns {ReactElement}
69
+     */
70
+    render() {
71
+        const routes = RouteRegistry.getRoutes();
72
+
73
+        return (
74
+            <Provider store = { this.props.store }>
75
+                <Router
76
+                    createElement = { this._routerCreateElement }
77
+                    history = { this.history }>
78
+                    { routes.map(r =>
79
+                        <Route
80
+                            component = { r.component }
81
+                            key = { r.component }
82
+                            path = { r.path } />
83
+                    ) }
84
+                </Router>
85
+            </Provider>
86
+        );
87
+    }
88
+
89
+    /**
90
+     * Navigates to a specific Route (via platform-specific means).
91
+     *
92
+     * @param {Route} route - The Route to which to navigate.
93
+     * @returns {void}
94
+     */
95
+    _navigate(route) {
96
+        let path = route.path;
97
+        const store = this.props.store;
98
+
99
+        // The syntax :room bellow is defined by react-router. It "matches a URL
100
+        // segment up to the next /, ?, or #. The matched string is called a
101
+        // param."
102
+        path
103
+            = path.replace(
104
+                /:room/g,
105
+                store.getState()['features/base/conference'].room);
106
+
107
+        return store.dispatch(push(path));
108
+    }
109
+
110
+    /**
111
+     * Invoked by react-router to notify this App that a Route is about to be
112
+     * rendered.
113
+     *
114
+     * @private
115
+     * @returns {void}
116
+     */
117
+    _onRouteEnter() {
118
+        // XXX The following is mandatory. Otherwise, moving back & forward
119
+        // through the browser's history could leave this App on the Conference
120
+        // page without a room name.
121
+
122
+        // Our Router configuration (at the time of this writing) is such that
123
+        // each Route corresponds to a single URL. Hence, entering into a Route
124
+        // is like opening a URL.
125
+
126
+        // XXX In order to unify work with URLs in web and native environments,
127
+        // we will construct URL here with correct domain from config.
128
+        const currentDomain = getDomain(this.props.store.getState);
129
+        const url
130
+            = new URL(window.location.pathname, `https://${currentDomain}`)
131
+                .toString();
132
+
133
+        this._openURL(url);
134
+    }
135
+
136
+    /**
137
+     * Create a ReactElement from the specified component and props on behalf of
138
+     * the associated Router.
139
+     *
140
+     * @param {Component} component - The component from which the ReactElement
141
+     * is to be created.
142
+     * @param {Object} props - The read-only React Component props with which
143
+     * the ReactElement is to be initialized.
144
+     * @private
145
+     * @returns {ReactElement}
146
+     */
147
+    _routerCreateElement(component, props) {
148
+        return this._createElement(component, props);
149
+    }
150
+}
151
+
152
+/**
153
+ * App component's property types.
154
+ *
155
+ * @static
156
+ */
157
+App.propTypes = AbstractApp.propTypes;

+ 33
- 1
react/features/base/lib-jitsi-meet/_.native.js Ver arquivo

@@ -1 +1,33 @@
1
-export * from './native';
1
+import './native';
2
+
3
+// The library lib-jitsi-meet (externally) depends on the libraries jQuery and
4
+// Strophe
5
+(global => {
6
+    // jQuery
7
+    if (typeof global.$ === 'undefined') {
8
+        const jQuery = require('jquery');
9
+
10
+        jQuery(global);
11
+        global.$ = jQuery;
12
+    }
13
+
14
+    // Strophe
15
+    if (typeof global.Strophe === 'undefined') {
16
+        require('strophe');
17
+        require('strophejs-plugins/disco/strophe.disco');
18
+        require('strophejs-plugins/caps/strophe.caps.jsonly');
19
+    }
20
+})(global || window || this); // eslint-disable-line no-invalid-this
21
+
22
+// Re-export JitsiMeetJS from the library lib-jitsi-meet to (the other features
23
+// of) the project jitsi-meet-react.
24
+//
25
+// TODO The Web support implemented by the jitsi-meet project explicitly uses
26
+// the library lib-jitsi-meet as a binary and keeps it out of the application
27
+// bundle. The mobile support implemented by the jitsi-meet-react project did
28
+// not get to keeping the lib-jitsi-meet library out of the application bundle
29
+// and even used it from source. As an intermediate step, start using the
30
+// library lib-jitsi-meet as a binary on mobile at the time of this writing. In
31
+// the future, implement not packaging it in the application bundle.
32
+import JitsiMeetJS from 'lib-jitsi-meet/lib-jitsi-meet.min';
33
+export { JitsiMeetJS as default };

+ 3
- 0
react/features/base/lib-jitsi-meet/_.web.js Ver arquivo

@@ -0,0 +1,3 @@
1
+/* global JitsiMeetJS */
2
+
3
+export default JitsiMeetJS;

+ 1
- 31
react/features/base/lib-jitsi-meet/index.js Ver arquivo

@@ -1,36 +1,6 @@
1
-import './_';
2
-
3
-// The library lib-jitsi-meet (externally) depends on the libraries jQuery and
4
-// Strophe
5
-(global => {
6
-    // jQuery
7
-    if (typeof global.$ === 'undefined') {
8
-        const jQuery = require('jquery');
9
-
10
-        jQuery(global);
11
-        global.$ = jQuery;
12
-    }
13
-
14
-    // Strophe
15
-    if (typeof global.Strophe === 'undefined') {
16
-        require('strophe');
17
-        require('strophejs-plugins/disco/strophe.disco');
18
-        require('strophejs-plugins/caps/strophe.caps.jsonly');
19
-    }
20
-})(global || window || this); // eslint-disable-line no-invalid-this
21
-
22 1
 // Re-export JitsiMeetJS from the library lib-jitsi-meet to (the other features
23 2
 // of) the project jitsi-meet-react.
24
-//
25
-// TODO The Web support implemented by the jitsi-meet project explicitly uses
26
-// the library lib-jitsi-meet as a binary and keeps it out of the application
27
-// bundle. The mobile support implemented by the jitsi-meet-react project did
28
-// not get to keeping the lib-jitsi-meet library out of the application bundle
29
-// and even used it from source. As an intermediate step, start using the
30
-// library lib-jitsi-meet as a binary on mobile at the time of this writing. In
31
-// the future, implement not packaging it in the application bundle.
32
-import JitsiMeetJS from 'lib-jitsi-meet/lib-jitsi-meet.min';
33
-
3
+import JitsiMeetJS from './_';
34 4
 export { JitsiMeetJS as default };
35 5
 
36 6
 export * from './actions';

plugin.header.text.html → react/features/base/media/components/_.web.js Ver arquivo


plugin.welcomepage.footer.html → react/features/base/util/loadScript.web.js Ver arquivo


react/features/conference/components/Conference.js → react/features/conference/components/Conference.native.js Ver arquivo


+ 133
- 0
react/features/conference/components/Conference.web.js Ver arquivo

@@ -0,0 +1,133 @@
1
+import React, { Component } from 'react';
2
+
3
+/**
4
+ * For legacy reasons, inline style for display none.
5
+ * @type {{display: string}}
6
+ */
7
+const DISPLAY_NONE_STYLE = {
8
+    display: 'none'
9
+};
10
+
11
+/**
12
+ * Implements a React Component which renders initial conference layout
13
+ */
14
+export default class Conference extends Component {
15
+
16
+    /**
17
+     * Implements React's {@link Component#render()}.
18
+     *
19
+     * @inheritdoc
20
+     * @returns {ReactElement}
21
+     */
22
+    render() {
23
+        return (
24
+            <div id = 'videoconference_page'>
25
+                <div id = 'mainToolbarContainer'>
26
+                    <div
27
+                        className = 'notice'
28
+                        id = 'notice'
29
+                        style = { DISPLAY_NONE_STYLE }>
30
+                        <span
31
+                            className = 'noticeText'
32
+                            id = 'noticeText' />
33
+                    </div>
34
+                    <div
35
+                        className = 'toolbar'
36
+                        id = 'mainToolbar' />
37
+                </div>
38
+                <div
39
+                    className = 'hide'
40
+                    id = 'subject' />
41
+                <div
42
+                    className = 'toolbar'
43
+                    id = 'extendedToolbar'>
44
+                    <div id = 'extendedToolbarButtons' />
45
+                    <a
46
+                        className = 'button icon-feedback'
47
+                        id = 'feedbackButton' />
48
+                    <div id = 'sideToolbarContainer' />
49
+                </div>
50
+                <div id = 'videospace'>
51
+                    <div
52
+                        className = 'videocontainer'
53
+                        id = 'largeVideoContainer'>
54
+                        <div id = 'sharedVideo'>
55
+                            <div id = 'sharedVideoIFrame' />
56
+                        </div>
57
+                        <div id = 'etherpad' />
58
+                        <a target = '_new'>
59
+                            <div className = 'watermark leftwatermark' />
60
+                        </a>
61
+                        <a target = '_new'>
62
+                            <div className = 'watermark rightwatermark' />
63
+                        </a>
64
+                        <a
65
+                            className = 'poweredby'
66
+                            href = 'http://jitsi.org'
67
+                            target = '_new'>
68
+                            <span data-i18n = 'poweredby' /> jitsi.org
69
+                        </a>
70
+                        <div id = 'dominantSpeaker'>
71
+                            <div className = 'dynamic-shadow' />
72
+                            <img
73
+                                id = 'dominantSpeakerAvatar'
74
+                                src = '' />
75
+                        </div>
76
+                        <span id = 'remoteConnectionMessage' />
77
+                        <div id = 'largeVideoWrapper'>
78
+                            <video
79
+                                autoPlay = { true }
80
+                                id = 'largeVideo'
81
+                                muted = 'true' />
82
+                        </div>
83
+                        <span id = 'localConnectionMessage' />
84
+                        <span
85
+                            className = 'video-state-indicator moveToCorner'
86
+                            id = 'videoResolutionLabel'>HD</span>
87
+                        <span
88
+                            className
89
+                                = 'video-state-indicator centeredVideoLabel'
90
+                            id = 'recordingLabel'>
91
+                            <span id = 'recordingLabelText' />
92
+                            <img
93
+                                className = 'recordingSpinner'
94
+                                id = 'recordingSpinner'
95
+                                src = 'images/spin.svg' />
96
+                        </span>
97
+                    </div>
98
+                    <div className = 'filmstrip'>
99
+                        <div
100
+                            className = 'filmstrip__videos'
101
+                            id = 'remoteVideos'>
102
+                            <span
103
+                                className = 'videocontainer'
104
+                                id = 'localVideoContainer'>
105
+                                <div
106
+                                    className = 'videocontainer__background' />
107
+                                <span id = 'localVideoWrapper' />
108
+                                <audio
109
+                                    autoPlay = { true }
110
+                                    id = 'localAudio'
111
+                                    muted = { true } />
112
+                                <div className = 'videocontainer__toolbar' />
113
+                                <div
114
+                                    className = 'videocontainer__toptoolbar' />
115
+                                <div
116
+                                    className
117
+                                        = 'videocontainer__hoverOverlay' />
118
+                            </span>
119
+                            <audio
120
+                                id = 'userJoined'
121
+                                preload = 'auto'
122
+                                src = 'sounds/joined.wav' />
123
+                            <audio
124
+                                id = 'userLeft'
125
+                                preload = 'auto'
126
+                                src = 'sounds/left.wav' />
127
+                        </div>
128
+                    </div>
129
+                </div>
130
+            </div>
131
+        );
132
+    }
133
+}

react/features/conference/components/ParticipantView.js → react/features/conference/components/ParticipantView.native.js Ver arquivo


+ 22
- 0
react/features/conference/components/ParticipantView.web.js Ver arquivo

@@ -0,0 +1,22 @@
1
+import { Component } from 'react';
2
+
3
+/**
4
+ * Implements a React Component which depicts a specific participant's avatar
5
+ * and video.
6
+ */
7
+export default class ParticipantView extends Component {
8
+
9
+   /**
10
+    * Implements React's {@link Component#render()}.
11
+    *
12
+    * @inheritdoc
13
+    * @returns {ReactElement|null}
14
+    */
15
+    render() {
16
+        // FIXME ParticipantView is supposed to be platform-independent.
17
+        // Temporarily though, ParticipantView is not in use on Web but has to
18
+        // exist in order to split App, Conference, and WelcomePage out of
19
+        // index.html.
20
+        return null;
21
+    }
22
+ }

+ 3
- 1
react/features/welcome/components/WelcomePage.native.js Ver arquivo

@@ -22,7 +22,9 @@ class WelcomePage extends AbstractWelcomePage {
22 22
     render() {
23 23
         return (
24 24
             <View style = { styles.container }>
25
-                { this._renderLocalVideo() }
25
+                {
26
+                    this._renderLocalVideo()
27
+                }
26 28
                 <View style = { styles.roomContainer }>
27 29
                     <Text style = { styles.title }>Enter room name</Text>
28 30
                     <TextInput

+ 150
- 0
react/features/welcome/components/WelcomePage.web.js Ver arquivo

@@ -0,0 +1,150 @@
1
+import React, { Component } from 'react';
2
+
3
+/**
4
+ * The web container rendering the welcome page.
5
+ */
6
+export default class WelcomePage extends Component {
7
+
8
+    /**
9
+     * Implements React's {@link Component#render()}.
10
+     *
11
+     * @inheritdoc
12
+     * @returns {ReactElement|null}
13
+     */
14
+    render() {
15
+        return (
16
+            <div id = 'welcome_page'>
17
+                {
18
+                    this._renderHeader()
19
+                }
20
+                {
21
+                    this._renderMain()
22
+                }
23
+            </div>
24
+        );
25
+    }
26
+
27
+    /**
28
+     * Renders a feature with a specific index.
29
+     *
30
+     * @param {number} index - The index of the feature to render.
31
+     * @private
32
+     * @returns {ReactElement}
33
+     */
34
+    _renderFeature(index) {
35
+        return (
36
+            <div className = 'feature_holder'>
37
+                <div
38
+                    className = 'feature_icon'
39
+                    data-i18n = { `welcomepage.feature${index}.title` } />
40
+                <div
41
+                    className = 'feature_description'
42
+                    data-i18n = { `welcomepage.feature${index}.content` }
43
+                    data-i18n-options = { JSON.stringify({
44
+                        postProcess: 'resolveAppName'
45
+                    }) } />
46
+            </div>
47
+        );
48
+    }
49
+
50
+    /**
51
+     * Renders a row of features.
52
+     *
53
+     * @param {number} beginIndex - The inclusive feature index to begin the row
54
+     * with.
55
+     * @param {number} endIndex - The exclusive feature index to end the row
56
+     * with.
57
+     * @private
58
+     * @returns {ReactElement}
59
+     */
60
+    _renderFeatureRow(beginIndex, endIndex) {
61
+        const features = [];
62
+
63
+        for (let index = beginIndex; index < endIndex; ++index) {
64
+            features.push(this._renderFeature(index));
65
+        }
66
+
67
+        return (
68
+            <div className = 'feature_row'>
69
+                {
70
+                    features
71
+                }
72
+            </div>
73
+        );
74
+    }
75
+
76
+    /**
77
+     * Renders the header part of this WelcomePage.
78
+     *
79
+     * @private
80
+     * @returns {ReactElement|null}
81
+     */
82
+    _renderHeader() {
83
+        return (
84
+            <div id = 'welcome_page_header'>
85
+                <a target = '_new'>
86
+                    <div className = 'watermark leftwatermark' />
87
+                </a>
88
+                <a target = '_new'>
89
+                    <div className = 'watermark rightwatermark' />
90
+                </a>
91
+                <a
92
+                    className = 'poweredby'
93
+                    href = 'http://jitsi.org'
94
+                    target = '_new'>
95
+                    <span data-i18n = 'poweredby' /> jitsi.org
96
+                </a>
97
+                <div id = 'enter_room_container'>
98
+                    <div id = 'enter_room_form'>
99
+                        <div id = 'domain_name' />
100
+                        <div id = 'enter_room'>
101
+                            <input
102
+                                autoFocus = { true }
103
+                                id = 'enter_room_field'
104
+                                type = 'text' />
105
+                            <div
106
+                                className = 'icon-reload'
107
+                                id = 'reload_roomname' />
108
+                            <input
109
+                                data-i18n = '[value]welcomepage.go'
110
+                                id = 'enter_room_button'
111
+                                type = 'button'
112
+                                value = 'GO' />
113
+                        </div>
114
+                    </div>
115
+                </div>
116
+                <div id = 'brand_header' />
117
+                <input
118
+                    id = 'disable_welcome'
119
+                    name = 'checkbox'
120
+                    type = 'checkbox' />
121
+                <label
122
+                    className = 'disable_welcome_position'
123
+                    data-i18n = 'welcomepage.disable'
124
+                    htmlFor = 'disable_welcome' />
125
+                <div id = 'header_text' />
126
+            </div>
127
+        );
128
+    }
129
+
130
+    /**
131
+     * Renders the main part of this WelcomePage.
132
+     *
133
+     * @private
134
+     * @returns {ReactElement|null}
135
+     */
136
+    _renderMain() {
137
+        return (
138
+            <div id = 'welcome_page_main'>
139
+                <div id = 'features'>
140
+                    {
141
+                        this._renderFeatureRow(1, 5)
142
+                    }
143
+                    {
144
+                        this._renderFeatureRow(5, 9)
145
+                    }
146
+                </div>
147
+            </div>
148
+        );
149
+    }
150
+}

+ 54
- 0
react/index.web.js Ver arquivo

@@ -0,0 +1,54 @@
1
+import React from 'react';
2
+import ReactDOM from 'react-dom';
3
+import { browserHistory } from 'react-router';
4
+import {
5
+    routerMiddleware,
6
+    routerReducer
7
+} from 'react-router-redux';
8
+import { compose, createStore } from 'redux';
9
+import Thunk from 'redux-thunk';
10
+
11
+import config from './config';
12
+import { App } from './features/app';
13
+import {
14
+    MiddlewareRegistry,
15
+    ReducerRegistry
16
+} from './features/base/redux';
17
+
18
+// Create combined reducer from all reducers in registry + routerReducer from
19
+// 'react-router-redux' module (stores location updates from history).
20
+// @see https://github.com/reactjs/react-router-redux#routerreducer.
21
+const reducer = ReducerRegistry.combineReducers({
22
+    routing: routerReducer
23
+});
24
+
25
+// Apply all registered middleware from the MiddlewareRegistry + additional
26
+// 3rd party middleware:
27
+// - Thunk - allows us to dispatch async actions easily. For more info
28
+// @see https://github.com/gaearon/redux-thunk.
29
+// - routerMiddleware - middleware from 'react-router-redux' module to track
30
+// changes in browser history inside Redux state. For more information
31
+// @see https://github.com/reactjs/react-router-redux.
32
+let middleware = MiddlewareRegistry.applyMiddleware(
33
+    Thunk,
34
+    routerMiddleware(browserHistory));
35
+
36
+// Try to enable Redux DevTools Chrome extension in order to make it available
37
+// for the purposes of facilitating development.
38
+let devToolsExtension;
39
+
40
+if (typeof window === 'object'
41
+        && (devToolsExtension = window.devToolsExtension)) {
42
+    middleware = compose(middleware, devToolsExtension());
43
+}
44
+
45
+// Create Redux store with our reducer and middleware.
46
+const store = createStore(reducer, middleware);
47
+
48
+// Render the main Component.
49
+ReactDOM.render(
50
+    <App
51
+        config = { config }
52
+        store = { store }
53
+        url = { window.location.toString() } />,
54
+    document.getElementById('react'));

Carregando…
Cancelar
Salvar