Procházet zdrojové kódy

feat(prejoin) Expose prejoin app

master
Tudor-Ovidiu Avram před 4 roky
rodič
revize
0e5091adba

+ 16
- 8
css/_premeeting-screens.scss Zobrazit soubor

1
 /**
1
 /**
2
  * Shared style for full screen local track based dialogs/modals.
2
  * Shared style for full screen local track based dialogs/modals.
3
  */
3
  */
4
-.premeeting-screen {
4
+ .premeeting-screen,
5
+  .preview-overlay {
6
+     position: absolute;
7
+     left: 0;
8
+     right: 0;
9
+     top: 0;
10
+     bottom: 0;
11
+  }
12
+
13
+ .premeeting-screen {
5
     align-items: stretch;
14
     align-items: stretch;
6
-    background: #1C2025;
7
-    bottom: 0;
15
+    background: radial-gradient(50% 50% at 50% 50%, #5D95C7 0%, #376288 100%), #FFFFFF;
8
     display: flex;
16
     display: flex;
9
     flex-direction: column;
17
     flex-direction: column;
10
     font-size: 1.3em;
18
     font-size: 1.3em;
11
-    left: 0;
12
-    position: absolute;
13
-    right: 0;
14
-    top: 0;
15
     z-index: $toolbarZ + 1;
19
     z-index: $toolbarZ + 1;
16
 
20
 
17
     .action-btn {
21
     .action-btn {
74
         }
78
         }
75
     }
79
     }
76
 
80
 
81
+    .preview-overlay {
82
+        background-image: linear-gradient(transparent, black);
83
+        z-index: $toolbarZ + 1;
84
+    }
85
+
77
     .content {
86
     .content {
78
         align-items: center;
87
         align-items: center;
79
-        background-image: linear-gradient(transparent, black);
80
         display: flex;
88
         display: flex;
81
         flex: 1;
89
         flex: 1;
82
         flex-direction: column;
90
         flex-direction: column;

+ 10
- 0
index.html Zobrazit soubor

8
 
8
 
9
     <link rel="apple-touch-icon" href="images/apple-touch-icon.png">
9
     <link rel="apple-touch-icon" href="images/apple-touch-icon.png">
10
     <link rel="stylesheet" href="css/all.css">
10
     <link rel="stylesheet" href="css/all.css">
11
+    <script>
12
+        document.addEventListener('DOMContentLoaded', () => {
13
+            if (!JitsiMeetJS.app) {
14
+                return;
15
+            }
11
 
16
 
17
+            JitsiMeetJS.app.renderEntryPoint({
18
+                Component: JitsiMeetJS.app.entryPoints.APP
19
+            })
20
+        })
21
+    </script>
12
     <script>
22
     <script>
13
         // IE11 and earlier can be identified via their user agent and be
23
         // IE11 and earlier can be identified via their user agent and be
14
         // redirected to a page that is known to have no newer js syntax.
24
         // redirected to a page that is known to have no newer js syntax.

+ 2
- 2
react/features/base/app/components/BaseApp.js Zobrazit soubor

122
      * @returns {ReactElement}
122
      * @returns {ReactElement}
123
      */
123
      */
124
     render() {
124
     render() {
125
-        const { route: { component }, store } = this.state;
125
+        const { route: { component, props }, store } = this.state;
126
 
126
 
127
         if (store) {
127
         if (store) {
128
             return (
128
             return (
129
                 <I18nextProvider i18n = { i18next }>
129
                 <I18nextProvider i18n = { i18next }>
130
                     <Provider store = { store }>
130
                     <Provider store = { store }>
131
                         <Fragment>
131
                         <Fragment>
132
-                            { this._createMainElement(component) }
132
+                            { this._createMainElement(component, props) }
133
                             <SoundCollection />
133
                             <SoundCollection />
134
                             { this._createExtraElement() }
134
                             { this._createExtraElement() }
135
                             { this._renderDialogContainer() }
135
                             { this._renderDialogContainer() }

+ 31
- 5
react/features/base/premeeting/components/web/PreMeetingScreen.js Zobrazit soubor

24
      */
24
      */
25
     name?: string,
25
     name?: string,
26
 
26
 
27
+    /**
28
+     * Indicates whether the avatar should be shown when video is off
29
+     */
30
+    showAvatar: boolean,
31
+
32
+    /**
33
+     * Indicates whether the label and copy url action should be shown
34
+     */
35
+    showConferenceInfo: boolean,
36
+
27
     /**
37
     /**
28
      * Title of the screen.
38
      * Title of the screen.
29
      */
39
      */
45
  * on the prejoin screen (pre-connection) or lobby (post-connection).
55
  * on the prejoin screen (pre-connection) or lobby (post-connection).
46
  */
56
  */
47
 export default class PreMeetingScreen extends PureComponent<Props> {
57
 export default class PreMeetingScreen extends PureComponent<Props> {
58
+    /**
59
+     * Default values for {@code Prejoin} component's properties.
60
+     *
61
+     * @static
62
+     */
63
+    static defaultProps = {
64
+        showAvatar: true,
65
+        showConferenceInfo: true
66
+    };
67
+
48
     /**
68
     /**
49
      * Implements {@code PureComponent#render}.
69
      * Implements {@code PureComponent#render}.
50
      *
70
      *
51
      * @inheritdoc
71
      * @inheritdoc
52
      */
72
      */
53
     render() {
73
     render() {
54
-        const { name, title, videoMuted, videoTrack } = this.props;
74
+        const { name, showAvatar, showConferenceInfo, title, videoMuted, videoTrack } = this.props;
55
 
75
 
56
         return (
76
         return (
57
             <div
77
             <div
59
                 id = 'lobby-screen'>
79
                 id = 'lobby-screen'>
60
                 <Preview
80
                 <Preview
61
                     name = { name }
81
                     name = { name }
82
+                    showAvatar = { showAvatar }
62
                     videoMuted = { videoMuted }
83
                     videoMuted = { videoMuted }
63
                     videoTrack = { videoTrack } />
84
                     videoTrack = { videoTrack } />
85
+                {!videoMuted && <div className = 'preview-overlay' />}
64
                 <div className = 'content'>
86
                 <div className = 'content'>
65
-                    <div className = 'title'>
66
-                        { title }
67
-                    </div>
68
-                    <CopyMeetingUrl />
87
+                    {showConferenceInfo && (
88
+                        <>
89
+                            <div className = 'title'>
90
+                                { title }
91
+                            </div>
92
+                            <CopyMeetingUrl />
93
+                        </>
94
+                    )}
69
                     { this.props.children }
95
                     { this.props.children }
70
                     <div className = 'media-btn-container'>
96
                     <div className = 'media-btn-container'>
71
                         <AudioSettingsButton visible = { true } />
97
                         <AudioSettingsButton visible = { true } />

+ 25
- 12
react/features/base/premeeting/components/web/Preview.js Zobrazit soubor

14
      */
14
      */
15
     name: string,
15
     name: string,
16
 
16
 
17
+    /**
18
+     * Indicates whether the avatar should be shown when video is off
19
+     */
20
+    showAvatar: boolean,
21
+
17
     /**
22
     /**
18
      * Flag signaling the visibility of camera preview.
23
      * Flag signaling the visibility of camera preview.
19
      */
24
      */
32
  * @returns {ReactElement}
37
  * @returns {ReactElement}
33
  */
38
  */
34
 function Preview(props: Props) {
39
 function Preview(props: Props) {
35
-    const { name, videoMuted, videoTrack } = props;
40
+    const { name, showAvatar, videoMuted, videoTrack } = props;
36
 
41
 
37
     if (!videoMuted && videoTrack) {
42
     if (!videoMuted && videoTrack) {
38
         return (
43
         return (
44
         );
49
         );
45
     }
50
     }
46
 
51
 
47
-    return (
48
-        <div
49
-            className = 'no-video'
50
-            id = 'preview'>
51
-            <Avatar
52
-                className = 'preview-avatar'
53
-                displayName = { name }
54
-                participantId = 'local'
55
-                size = { 200 } />
56
-        </div>
57
-    );
52
+    if (showAvatar) {
53
+        return (
54
+            <div
55
+                className = 'no-video'
56
+                id = 'preview'>
57
+                <Avatar
58
+                    className = 'preview-avatar'
59
+                    displayName = { name }
60
+                    participantId = 'local'
61
+                    size = { 200 } />
62
+            </div>
63
+        );
64
+    }
65
+
66
+    return null;
58
 }
67
 }
59
 
68
 
69
+Preview.defaultProps = {
70
+    showAvatar: true
71
+};
72
+
60
 /**
73
 /**
61
  * Maps part of the Redux state to the props of this component.
74
  * Maps part of the Redux state to the props of this component.
62
  *
75
  *

+ 84
- 1
react/features/base/tracks/functions.js Zobrazit soubor

1
 /* global APP */
1
 /* global APP */
2
 
2
 
3
 import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
3
 import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
4
-import { MEDIA_TYPE } from '../media';
4
+import { MEDIA_TYPE, setAudioMuted } from '../media';
5
 import {
5
 import {
6
     getUserSelectedCameraDeviceId,
6
     getUserSelectedCameraDeviceId,
7
     getUserSelectedMicDeviceId
7
     getUserSelectedMicDeviceId
125
         }));
125
         }));
126
 }
126
 }
127
 
127
 
128
+/**
129
+ * Returns an object containing a promise which resolves with the created tracks &
130
+ * the errors resulting from that process.
131
+ *
132
+ * @returns {Promise<JitsiLocalTrack>}
133
+ *
134
+ * @todo Refactor to not use APP
135
+ */
136
+export function createPrejoinTracks() {
137
+    const errors = {};
138
+    const initialDevices = [ 'audio' ];
139
+    const requestedAudio = true;
140
+    let requestedVideo = false;
141
+    const { startAudioOnly, startWithAudioMuted, startWithVideoMuted } = APP.store.getState()['features/base/settings'];
142
+
143
+    // Always get a handle on the audio input device so that we have statistics even if the user joins the
144
+    // conference muted. Previous implementation would only acquire the handle when the user first unmuted,
145
+    // which would results in statistics ( such as "No audio input" or "Are you trying to speak?") being available
146
+    // only after that point.
147
+    if (startWithAudioMuted) {
148
+        APP.store.dispatch(setAudioMuted(true));
149
+    }
150
+
151
+    if (!startWithVideoMuted && !startAudioOnly) {
152
+        initialDevices.push('video');
153
+        requestedVideo = true;
154
+    }
155
+
156
+    let tryCreateLocalTracks;
157
+
158
+    if (!requestedAudio && !requestedVideo) {
159
+        // Resolve with no tracks
160
+        tryCreateLocalTracks = Promise.resolve([]);
161
+    } else {
162
+        tryCreateLocalTracks = createLocalTracksF({ devices: initialDevices }, true)
163
+                .catch(err => {
164
+                    if (requestedAudio && requestedVideo) {
165
+
166
+                        // Try audio only...
167
+                        errors.audioAndVideoError = err;
168
+
169
+                        return (
170
+                            createLocalTracksF({ devices: [ 'audio' ] }, true));
171
+                    } else if (requestedAudio && !requestedVideo) {
172
+                        errors.audioOnlyError = err;
173
+
174
+                        return [];
175
+                    } else if (requestedVideo && !requestedAudio) {
176
+                        errors.videoOnlyError = err;
177
+
178
+                        return [];
179
+                    }
180
+                    logger.error('Should never happen');
181
+                })
182
+                .catch(err => {
183
+                    // Log this just in case...
184
+                    if (!requestedAudio) {
185
+                        logger.error('The impossible just happened', err);
186
+                    }
187
+                    errors.audioOnlyError = err;
188
+
189
+                    // Try video only...
190
+                    return requestedVideo
191
+                        ? createLocalTracksF({ devices: [ 'video' ] }, true)
192
+                        : [];
193
+                })
194
+                .catch(err => {
195
+                    // Log this just in case...
196
+                    if (!requestedVideo) {
197
+                        logger.error('The impossible just happened', err);
198
+                    }
199
+                    errors.videoOnlyError = err;
200
+
201
+                    return [];
202
+                });
203
+    }
204
+
205
+    return {
206
+        tryCreateLocalTracks,
207
+        errors
208
+    };
209
+}
210
+
128
 /**
211
 /**
129
  * Returns local audio track.
212
  * Returns local audio track.
130
  *
213
  *

+ 4
- 0
react/features/base/tracks/middleware.js Zobrazit soubor

143
         if (typeof APP !== 'undefined') {
143
         if (typeof APP !== 'undefined') {
144
             const result = next(action);
144
             const result = next(action);
145
 
145
 
146
+            if (isPrejoinPageVisible(store.getState())) {
147
+                return result;
148
+            }
149
+
146
             const { jitsiTrack } = action.track;
150
             const { jitsiTrack } = action.track;
147
             const muted = jitsiTrack.isMuted();
151
             const muted = jitsiTrack.isMuted();
148
             const participantID = jitsiTrack.getParticipantId();
152
             const participantID = jitsiTrack.getParticipantId();

+ 74
- 49
react/features/prejoin/components/Prejoin.js Zobrazit soubor

79
      */
79
      */
80
     setJoinByPhoneDialogVisiblity: Function,
80
     setJoinByPhoneDialogVisiblity: Function,
81
 
81
 
82
+    /**
83
+     * Indicates whether the avatar should be shown when video is off
84
+     */
85
+    showAvatar: boolean,
86
+
82
     /**
87
     /**
83
      * Flag signaling the visibility of camera preview.
88
      * Flag signaling the visibility of camera preview.
84
      */
89
      */
85
     showCameraPreview: boolean,
90
     showCameraPreview: boolean,
86
 
91
 
92
+    /**
93
+     * Flag signaling the visibility of join label, input and buttons
94
+     */
95
+    showJoinActions: boolean,
96
+
87
     /**
97
     /**
88
      * If 'JoinByPhoneDialog' is visible or not.
98
      * If 'JoinByPhoneDialog' is visible or not.
89
      */
99
      */
112
  * This component is displayed before joining a meeting.
122
  * This component is displayed before joining a meeting.
113
  */
123
  */
114
 class Prejoin extends Component<Props, State> {
124
 class Prejoin extends Component<Props, State> {
125
+    /**
126
+     * Default values for {@code Prejoin} component's properties.
127
+     *
128
+     * @static
129
+     */
130
+    static defaultProps = {
131
+        showJoinActions: true
132
+    };
133
+
115
     /**
134
     /**
116
      * Initializes a new {@code Prejoin} instance.
135
      * Initializes a new {@code Prejoin} instance.
117
      *
136
      *
223
             joinConference,
242
             joinConference,
224
             joinConferenceWithoutAudio,
243
             joinConferenceWithoutAudio,
225
             name,
244
             name,
245
+            showAvatar,
226
             showCameraPreview,
246
             showCameraPreview,
227
             showDialog,
247
             showDialog,
248
+            showJoinActions,
228
             t,
249
             t,
229
             videoTrack
250
             videoTrack
230
         } = this.props;
251
         } = this.props;
236
             <PreMeetingScreen
257
             <PreMeetingScreen
237
                 footer = { this._renderFooter() }
258
                 footer = { this._renderFooter() }
238
                 name = { name }
259
                 name = { name }
260
+                showAvatar = { showAvatar }
261
+                showConferenceInfo = { showJoinActions }
239
                 title = { t('prejoin.joinMeeting') }
262
                 title = { t('prejoin.joinMeeting') }
240
                 videoMuted = { !showCameraPreview }
263
                 videoMuted = { !showCameraPreview }
241
                 videoTrack = { videoTrack }>
264
                 videoTrack = { videoTrack }>
242
-                <div className = 'prejoin-input-area-container'>
243
-                    <div className = 'prejoin-input-area'>
244
-                        <InputField
245
-                            onChange = { _setName }
246
-                            onSubmit = { joinConference }
247
-                            placeHolder = { t('dialog.enterDisplayName') }
248
-                            value = { name } />
249
-
250
-                        <div className = 'prejoin-preview-dropdown-container'>
251
-                            <InlineDialog
252
-                                content = { <div className = 'prejoin-preview-dropdown-btns'>
253
-                                    <div
254
-                                        className = 'prejoin-preview-dropdown-btn'
255
-                                        onClick = { joinConferenceWithoutAudio }>
256
-                                        <Icon
257
-                                            className = 'prejoin-preview-dropdown-icon'
258
-                                            size = { 24 }
259
-                                            src = { IconVolumeOff } />
260
-                                        { t('prejoin.joinWithoutAudio') }
261
-                                    </div>
262
-                                    {hasJoinByPhoneButton && <div
263
-                                        className = 'prejoin-preview-dropdown-btn'
264
-                                        onClick = { _showDialog }>
265
-                                        <Icon
266
-                                            className = 'prejoin-preview-dropdown-icon'
267
-                                            size = { 24 }
268
-                                            src = { IconPhone } />
269
-                                        { t('prejoin.joinAudioByPhone') }
270
-                                    </div>}
271
-                                </div> }
272
-                                isOpen = { showJoinByPhoneButtons }
273
-                                onClose = { _onDropdownClose }>
274
-                                <ActionButton
275
-                                    disabled = { joinButtonDisabled }
276
-                                    hasOptions = { true }
277
-                                    onClick = { joinConference }
278
-                                    onOptionsClick = { _onOptionsClick }
279
-                                    type = 'primary'>
280
-                                    { t('prejoin.joinMeeting') }
281
-                                </ActionButton>
282
-                            </InlineDialog>
265
+                {showJoinActions && (
266
+                    <div className = 'prejoin-input-area-container'>
267
+                        <div className = 'prejoin-input-area'>
268
+                            <InputField
269
+                                onChange = { _setName }
270
+                                onSubmit = { joinConference }
271
+                                placeHolder = { t('dialog.enterDisplayName') }
272
+                                value = { name } />
273
+
274
+                            <div className = 'prejoin-preview-dropdown-container'>
275
+                                <InlineDialog
276
+                                    content = { <div className = 'prejoin-preview-dropdown-btns'>
277
+                                        <div
278
+                                            className = 'prejoin-preview-dropdown-btn'
279
+                                            onClick = { joinConferenceWithoutAudio }>
280
+                                            <Icon
281
+                                                className = 'prejoin-preview-dropdown-icon'
282
+                                                size = { 24 }
283
+                                                src = { IconVolumeOff } />
284
+                                            { t('prejoin.joinWithoutAudio') }
285
+                                        </div>
286
+                                        {hasJoinByPhoneButton && <div
287
+                                            className = 'prejoin-preview-dropdown-btn'
288
+                                            onClick = { _showDialog }>
289
+                                            <Icon
290
+                                                className = 'prejoin-preview-dropdown-icon'
291
+                                                size = { 24 }
292
+                                                src = { IconPhone } />
293
+                                            { t('prejoin.joinAudioByPhone') }
294
+                                        </div>}
295
+                                    </div> }
296
+                                    isOpen = { showJoinByPhoneButtons }
297
+                                    onClose = { _onDropdownClose }>
298
+                                    <ActionButton
299
+                                        disabled = { joinButtonDisabled }
300
+                                        hasOptions = { true }
301
+                                        onClick = { joinConference }
302
+                                        onOptionsClick = { _onOptionsClick }
303
+                                        type = 'primary'>
304
+                                        { t('prejoin.joinMeeting') }
305
+                                    </ActionButton>
306
+                                </InlineDialog>
307
+                            </div>
283
                         </div>
308
                         </div>
284
-                    </div>
285
 
309
 
286
-                    <div className = 'prejoin-checkbox-container'>
287
-                        <input
288
-                            className = 'prejoin-checkbox'
289
-                            onChange = { _onCheckboxChange }
290
-                            type = 'checkbox' />
291
-                        <span>{t('prejoin.doNotShow')}</span>
310
+                        <div className = 'prejoin-checkbox-container'>
311
+                            <input
312
+                                className = 'prejoin-checkbox'
313
+                                onChange = { _onCheckboxChange }
314
+                                type = 'checkbox' />
315
+                            <span>{t('prejoin.doNotShow')}</span>
316
+                        </div>
292
                     </div>
317
                     </div>
293
-                </div>
318
+                )}
294
                 { showDialog && (
319
                 { showDialog && (
295
                     <JoinByPhoneDialog
320
                     <JoinByPhoneDialog
296
                         joinConferenceWithoutAudio = { joinConferenceWithoutAudio }
321
                         joinConferenceWithoutAudio = { joinConferenceWithoutAudio }

+ 93
- 0
react/features/prejoin/components/PrejoinApp.js Zobrazit soubor

1
+// @flow
2
+
3
+import { AtlasKitThemeProvider } from '@atlaskit/theme';
4
+import React from 'react';
5
+
6
+import { BaseApp } from '../../../features/base/app';
7
+import { setConfig } from '../../base/config';
8
+import { createPrejoinTracks } from '../../base/tracks';
9
+import { initPrejoin } from '../actions';
10
+
11
+import Prejoin from './Prejoin';
12
+
13
+type Props = {
14
+
15
+    /**
16
+     * Indicates whether the avatar should be shown when video is off
17
+     */
18
+    showAvatar: boolean,
19
+
20
+    /**
21
+     * Flag signaling the visibility of join label, input and buttons
22
+     */
23
+    showJoinActions: boolean,
24
+};
25
+
26
+/**
27
+ * Wrapper application for prejoin.
28
+ *
29
+ * @extends BaseApp
30
+ */
31
+export default class PrejoinApp extends BaseApp<Props> {
32
+    _init: Promise<*>;
33
+
34
+    /**
35
+     * Navigates to {@link Prejoin} upon mount.
36
+     *
37
+     * @returns {void}
38
+     */
39
+    componentDidMount() {
40
+        super.componentDidMount();
41
+
42
+        this._init.then(async () => {
43
+            const { store } = this.state;
44
+            const { dispatch } = store;
45
+            const { showAvatar, showJoinActions } = this.props;
46
+
47
+            super._navigate({
48
+                component: Prejoin,
49
+                props: {
50
+                    showAvatar,
51
+                    showJoinActions
52
+                }
53
+            });
54
+
55
+            const { startWithAudioMuted, startWithVideoMuted } = store.getState()['features/base/settings'];
56
+
57
+            dispatch(setConfig({
58
+                prejoinPageEnabled: true,
59
+                startWithAudioMuted,
60
+                startWithVideoMuted
61
+            }));
62
+
63
+            const { tryCreateLocalTracks, errors } = createPrejoinTracks();
64
+
65
+            const tracks = await tryCreateLocalTracks;
66
+
67
+            dispatch(initPrejoin(tracks, errors));
68
+        });
69
+    }
70
+
71
+    /**
72
+     * Overrides the parent method to inject {@link AtlasKitThemeProvider} as
73
+     * the top most component.
74
+     *
75
+     * @override
76
+     */
77
+    _createMainElement(component, props) {
78
+        return (
79
+            <AtlasKitThemeProvider mode = 'dark'>
80
+                { super._createMainElement(component, props) }
81
+            </AtlasKitThemeProvider>
82
+        );
83
+    }
84
+
85
+    /**
86
+     * Renders the platform specific dialog container.
87
+     *
88
+     * @returns {React$Element}
89
+     */
90
+    _renderDialogContainer() {
91
+        return null;
92
+    }
93
+}

+ 20
- 3
react/index.web.js Zobrazit soubor

8
 import { App } from './features/app/components';
8
 import { App } from './features/app/components';
9
 import { getLogger } from './features/base/logging/functions';
9
 import { getLogger } from './features/base/logging/functions';
10
 import { Platform } from './features/base/react';
10
 import { Platform } from './features/base/react';
11
+import { getJitsiMeetGlobalNS } from './features/base/util';
12
+import PrejoinApp from './features/prejoin/components/PrejoinApp';
11
 
13
 
12
 const logger = getLogger('index.web');
14
 const logger = getLogger('index.web');
13
 const OS = Platform.OS;
15
 const OS = Platform.OS;
20
 
22
 
21
     APP.connectionTimes['document.ready'] = now;
23
     APP.connectionTimes['document.ready'] = now;
22
     logger.log('(TIME) document ready:\t', now);
24
     logger.log('(TIME) document ready:\t', now);
23
-
24
-    // Render the main/root Component.
25
-    ReactDOM.render(<App />, document.getElementById('react'));
26
 });
25
 });
27
 
26
 
28
 // Workaround for the issue when returning to a page with the back button and
27
 // Workaround for the issue when returning to a page with the back button and
56
     APP.API.dispose();
55
     APP.API.dispose();
57
     getJitsiMeetTransport().dispose();
56
     getJitsiMeetTransport().dispose();
58
 });
57
 });
58
+
59
+const globalNS = getJitsiMeetGlobalNS();
60
+
61
+globalNS.entryPoints = {
62
+    APP: App,
63
+    PREJOIN: PrejoinApp
64
+};
65
+
66
+globalNS.renderEntryPoint = ({
67
+    Component,
68
+    props = {},
69
+    elementId = 'react'
70
+}) => {
71
+    ReactDOM.render(
72
+        <Component { ...props } />,
73
+        document.getElementById(elementId)
74
+    );
75
+};

+ 41
- 0
static/prejoin.html Zobrazit soubor

1
+<html xmlns="http://www.w3.org/1999/html">
2
+  <head>
3
+    <meta charset="utf-8">
4
+    <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <!--#include virtual="/base.html" -->
7
+    <link rel="stylesheet" href="../css/all.css">
8
+    <script>
9
+      document.addEventListener('DOMContentLoaded', () => {
10
+          if (!JitsiMeetJS.app) {
11
+            return;
12
+          }
13
+
14
+          const url = new URL(window.location.href);
15
+          const params = new URLSearchParams(url.search);
16
+          const showAvatar = params.get('showAvatar') === 'true';
17
+          const showJoinActions = params.get('showJoinActions') === 'true';
18
+          const css = params.get('style');
19
+          const style = document.createElement('style');
20
+          style.appendChild(document.createTextNode(css));
21
+          document.head.appendChild(style);
22
+
23
+          JitsiMeetJS.app.renderEntryPoint({
24
+              Component: JitsiMeetJS.app.entryPoints.PREJOIN,
25
+              props: {
26
+                showAvatar,
27
+                showJoinActions
28
+              }
29
+          })
30
+      })
31
+    </script>
32
+    <!--#include virtual="/title.html" -->
33
+    <script>var config = {}</script><!-- adapt to your needs, i.e. set hosts and bosh path -->
34
+    <script>var interfaceConfig = {}</script>
35
+    <script src="../libs/lib-jitsi-meet.min.js?v=139"></script>
36
+    <script src="../libs/app.bundle.min.js?v=139"></script>
37
+  </head>
38
+  <body>
39
+    <div id="react"></div>
40
+  </body>
41
+</html>

Načítá se…
Zrušit
Uložit