浏览代码

Comply w/ coding style

j8
Lyubo Marinov 8 年前
父节点
当前提交
fd10362bef

+ 3
- 3
react/features/base/conference/actions.js 查看文件

453
  * @param {(string|undefined)} room - The name of the room of the conference to
453
  * @param {(string|undefined)} room - The name of the room of the conference to
454
  * be joined.
454
  * be joined.
455
  * @returns {{
455
  * @returns {{
456
- *      type: SET_ROOM,
457
- *      room: string
458
- *  }}
456
+ *     type: SET_ROOM,
457
+ *     room: string
458
+ * }}
459
  */
459
  */
460
 export function setRoom(room) {
460
 export function setRoom(room) {
461
     return {
461
     return {

+ 29
- 27
react/features/desktop-picker/actions.js 查看文件

1
-import { getLogger } from 'jitsi-meet-logger';
2
-
3
 import { openDialog } from '../base/dialog';
1
 import { openDialog } from '../base/dialog';
2
+
4
 import {
3
 import {
5
     RESET_DESKTOP_SOURCES,
4
     RESET_DESKTOP_SOURCES,
6
     UPDATE_DESKTOP_SOURCES
5
     UPDATE_DESKTOP_SOURCES
7
 } from './actionTypes';
6
 } from './actionTypes';
8
 import { DesktopPicker } from './components';
7
 import { DesktopPicker } from './components';
9
 
8
 
10
-const logger = getLogger(__filename);
11
-
12
-/**
13
- * Signals to remove all stored DesktopCapturerSources.
14
- *
15
- * @returns {{
16
- *     type: RESET_DESKTOP_SOURCES
17
- * }}
18
- */
19
-export function resetDesktopSources() {
20
-    return {
21
-        type: RESET_DESKTOP_SOURCES
22
-    };
23
-}
9
+const logger = require('jitsi-meet-logger').getLogger(__filename);
24
 
10
 
25
 /**
11
 /**
26
  * Begins a request to get available DesktopCapturerSources.
12
  * Begins a request to get available DesktopCapturerSources.
27
  *
13
  *
28
  * @param {Array} types - An array with DesktopCapturerSource type strings.
14
  * @param {Array} types - An array with DesktopCapturerSource type strings.
29
- * @param {Object} options - Additional configuration for getting a list
30
- * of sources.
31
- * @param {Object} options.thumbnailSize - The desired height and width
32
- * of the return native image object used for the preview image of the source.
15
+ * @param {Object} options - Additional configuration for getting a list of
16
+ * sources.
17
+ * @param {Object} options.thumbnailSize - The desired height and width of the
18
+ * return native image object used for the preview image of the source.
33
  * @returns {Function}
19
  * @returns {Function}
34
  */
20
  */
35
 export function obtainDesktopSources(types, options = {}) {
21
 export function obtainDesktopSources(types, options = {}) {
42
     }
28
     }
43
 
29
 
44
     return dispatch => {
30
     return dispatch => {
45
-        if (window.JitsiMeetElectron
46
-            && window.JitsiMeetElectron.obtainDesktopStreams) {
47
-            window.JitsiMeetElectron.obtainDesktopStreams(
31
+        const { JitsiMeetElectron } = window;
32
+
33
+        if (JitsiMeetElectron && JitsiMeetElectron.obtainDesktopStreams) {
34
+            JitsiMeetElectron.obtainDesktopStreams(
48
                 sources => dispatch(updateDesktopSources(sources)),
35
                 sources => dispatch(updateDesktopSources(sources)),
49
-                error => logger.error(
50
-                    `Error while obtaining desktop sources: ${error}`),
36
+                error =>
37
+                    logger.error(
38
+                        `Error while obtaining desktop sources: ${error}`),
51
                 capturerOptions
39
                 capturerOptions
52
             );
40
             );
53
         } else {
41
         } else {
54
-            logger.error('Called JitsiMeetElectron.obtainDesktopStreams '
55
-                + 'but it is not defined');
42
+            logger.error(
43
+                'Called JitsiMeetElectron.obtainDesktopStreams'
44
+                    + ' but it is not defined');
56
         }
45
         }
57
     };
46
     };
58
 }
47
 }
59
 
48
 
49
+/**
50
+ * Signals to remove all stored DesktopCapturerSources.
51
+ *
52
+ * @returns {{
53
+ *     type: RESET_DESKTOP_SOURCES
54
+ * }}
55
+ */
56
+export function resetDesktopSources() {
57
+    return {
58
+        type: RESET_DESKTOP_SOURCES
59
+    };
60
+}
61
+
60
 /**
62
 /**
61
  * Signals to open a dialog with the DesktopPicker component.
63
  * Signals to open a dialog with the DesktopPicker component.
62
  *
64
  *

+ 102
- 97
react/features/desktop-picker/components/DesktopPicker.js 查看文件

6
 
6
 
7
 import { Dialog, hideDialog } from '../../base/dialog';
7
 import { Dialog, hideDialog } from '../../base/dialog';
8
 import { translate } from '../../base/i18n';
8
 import { translate } from '../../base/i18n';
9
-import {
10
-    resetDesktopSources,
11
-    obtainDesktopSources
12
-} from '../actions';
9
+
10
+import { obtainDesktopSources, resetDesktopSources } from '../actions';
13
 import DesktopPickerPane from './DesktopPickerPane';
11
 import DesktopPickerPane from './DesktopPickerPane';
14
 
12
 
15
-const updateInterval = 1000;
16
-const thumbnailSize = {
13
+const THUMBNAIL_SIZE = {
17
     height: 300,
14
     height: 300,
18
     width: 300
15
     width: 300
19
 };
16
 };
20
-const tabConfigurations = [
17
+const UPDATE_INTERVAL = 1000;
18
+
19
+const TAB_CONFIGURATIONS = [
21
     {
20
     {
21
+        /**
22
+         * The indicator which determines whether this tab configuration is
23
+         * selected by default.
24
+         *
25
+         * @type {boolean}
26
+         */
27
+        defaultSelected: true,
22
         label: 'dialog.yourEntireScreen',
28
         label: 'dialog.yourEntireScreen',
23
-        type: 'screen',
24
-        isDefault: true
29
+        type: 'screen'
25
     },
30
     },
26
     {
31
     {
27
         label: 'dialog.applicationWindow',
32
         label: 'dialog.applicationWindow',
28
         type: 'window'
33
         type: 'window'
29
     }
34
     }
30
 ];
35
 ];
31
-
32
-const validTypes = tabConfigurations.map(configuration => configuration.type);
33
-const configuredTypes = config.desktopSharingChromeSources || [];
34
-
35
-const tabsToPopulate = tabConfigurations.filter(configuration =>
36
-    configuredTypes.includes(configuration.type)
37
-    && validTypes.includes(configuration.type)
38
-);
39
-const typesToFetch = tabsToPopulate.map(configuration => configuration.type);
36
+const CONFIGURED_TYPES = config.desktopSharingChromeSources || [];
37
+const VALID_TYPES = TAB_CONFIGURATIONS.map(c => c.type);
38
+const TABS_TO_POPULATE
39
+    = TAB_CONFIGURATIONS.filter(
40
+        c => CONFIGURED_TYPES.includes(c.type) && VALID_TYPES.includes(c.type));
41
+const TYPES_TO_FETCH = TABS_TO_POPULATE.map(c => c.type);
40
 
42
 
41
 /**
43
 /**
42
  * React component for DesktopPicker.
44
  * React component for DesktopPicker.
56
         dispatch: React.PropTypes.func,
58
         dispatch: React.PropTypes.func,
57
 
59
 
58
         /**
60
         /**
59
-         * The callback to be invoked when the component is closed or
60
-         * when a DesktopCapturerSource has been chosen.
61
+         * The callback to be invoked when the component is closed or when
62
+         * a DesktopCapturerSource has been chosen.
61
          */
63
          */
62
         onSourceChoose: React.PropTypes.func,
64
         onSourceChoose: React.PropTypes.func,
63
 
65
 
64
         /**
66
         /**
65
-         * An object with arrays of DesktopCapturerSources. The key
66
-         * should be the source type.
67
+         * An object with arrays of DesktopCapturerSources. The key should be
68
+         * the source type.
67
          */
69
          */
68
         sources: React.PropTypes.object,
70
         sources: React.PropTypes.object,
69
 
71
 
94
     }
96
     }
95
 
97
 
96
     /**
98
     /**
97
-     * Perform an immediate update request for DesktopCapturerSources and
98
-     * begin requesting updates at an interval.
99
+     * Perform an immediate update request for DesktopCapturerSources and begin
100
+     * requesting updates at an interval.
99
      *
101
      *
100
      * @inheritdoc
102
      * @inheritdoc
101
      */
103
      */
104
         this._startPolling();
106
         this._startPolling();
105
     }
107
     }
106
 
108
 
107
-    /**
108
-     * Clean up component and DesktopCapturerSource store state.
109
-     *
110
-     * @inheritdoc
111
-     */
112
-    componentWillUnmount() {
113
-        this._stopPolling();
114
-        this.props.dispatch(resetDesktopSources());
115
-    }
116
-
117
     /**
109
     /**
118
      * Notifies this mounted React Component that it will receive new props.
110
      * Notifies this mounted React Component that it will receive new props.
119
      * Sets a default selected source if one is not already set.
111
      * Sets a default selected source if one is not already set.
125
      */
117
      */
126
     componentWillReceiveProps(nextProps) {
118
     componentWillReceiveProps(nextProps) {
127
         if (!this.state.selectedSourceId
119
         if (!this.state.selectedSourceId
128
-            && nextProps.sources.screen.length) {
129
-            this.setState({ selectedSourceId: nextProps.sources.screen[0].id });
120
+                && nextProps.sources.screen.length) {
121
+            this.setState({
122
+                selectedSourceId: nextProps.sources.screen[0].id
123
+            });
130
         }
124
         }
131
     }
125
     }
132
 
126
 
127
+    /**
128
+     * Clean up component and DesktopCapturerSource store state.
129
+     *
130
+     * @inheritdoc
131
+     */
132
+    componentWillUnmount() {
133
+        this._stopPolling();
134
+        this.props.dispatch(resetDesktopSources());
135
+    }
136
+
133
     /**
137
     /**
134
      * Implements React's {@link Component#render()}.
138
      * Implements React's {@link Component#render()}.
135
      *
139
      *
145
                 titleKey = 'dialog.shareYourScreen'
149
                 titleKey = 'dialog.shareYourScreen'
146
                 width = 'medium' >
150
                 width = 'medium' >
147
                 { this._renderTabs() }
151
                 { this._renderTabs() }
148
-            </Dialog>);
152
+            </Dialog>
153
+        );
149
     }
154
     }
150
 
155
 
151
     /**
156
     /**
152
-     * Dispatches an action to get currently available DesktopCapturerSources.
157
+     * Dispatches an action to hide the DesktopPicker and invokes the passed in
158
+     * callback with a selectedSourceId, if any.
153
      *
159
      *
154
-     * @private
160
+     * @param {string} id - The id of the DesktopCapturerSource to pass into the
161
+     * onSourceChoose callback.
155
      * @returns {void}
162
      * @returns {void}
156
      */
163
      */
157
-    _updateSources() {
158
-        this.props.dispatch(obtainDesktopSources(
159
-            typesToFetch,
160
-            {
161
-                thumbnailSize
162
-            }
163
-        ));
164
+    _onCloseModal(id = '') {
165
+        this.props.onSourceChoose(id);
166
+        this.props.dispatch(hideDialog());
164
     }
167
     }
165
 
168
 
166
     /**
169
     /**
167
-     * Create an interval to update knwon available DesktopCapturerSources.
170
+     * Sets the currently selected DesktopCapturerSource.
168
      *
171
      *
169
-     * @private
172
+     * @param {string} id - The id of DesktopCapturerSource.
170
      * @returns {void}
173
      * @returns {void}
171
      */
174
      */
172
-    _startPolling() {
173
-        this._stopPolling();
174
-        this._poller = window.setInterval(this._updateSources,
175
-            updateInterval);
175
+    _onPreviewClick(id) {
176
+        this.setState({ selectedSourceId: id });
176
     }
177
     }
177
 
178
 
178
     /**
179
     /**
179
-     * Cancels the interval to update DesktopCapturerSources.
180
+     * Request to close the modal and execute callbacks with the selected source
181
+     * id.
180
      *
182
      *
181
-     * @private
182
      * @returns {void}
183
      * @returns {void}
183
      */
184
      */
184
-    _stopPolling() {
185
-        window.clearInterval(this._poller);
186
-        this._poller = null;
185
+    _onSubmit() {
186
+        this._onCloseModal(this.state.selectedSourceId);
187
     }
187
     }
188
 
188
 
189
     /**
189
     /**
190
-     * Sets the currently selected DesktopCapturerSource.
190
+     * Configures and renders the tabs for display.
191
      *
191
      *
192
-     * @param {string} id - The id of DesktopCapturerSource.
193
-     * @returns {void}
192
+     * @private
193
+     * @returns {ReactElement}
194
      */
194
      */
195
-    _onPreviewClick(id) {
196
-        this.setState({ selectedSourceId: id });
195
+    _renderTabs() {
196
+        const { selectedSourceId } = this.state;
197
+        const { sources, t } = this.props;
198
+        const tabs
199
+            = TABS_TO_POPULATE.map(({ defaultSelected, label, type }) => {
200
+                return {
201
+                    content: <DesktopPickerPane
202
+                        key = { type }
203
+                        onClick = { this._onPreviewClick }
204
+                        onDoubleClick = { this._onCloseModal }
205
+                        selectedSourceId = { selectedSourceId }
206
+                        sources = { sources[type] || [] }
207
+                        type = { type } />,
208
+                    defaultSelected,
209
+                    label: t(label)
210
+                };
211
+            });
212
+
213
+        return <Tabs tabs = { tabs } />;
197
     }
214
     }
198
 
215
 
199
     /**
216
     /**
200
-     * Request to close the modal and execute callbacks
201
-     * with the selected source id.
217
+     * Create an interval to update knwon available DesktopCapturerSources.
202
      *
218
      *
219
+     * @private
203
      * @returns {void}
220
      * @returns {void}
204
      */
221
      */
205
-    _onSubmit() {
206
-        this._onCloseModal(this.state.selectedSourceId);
222
+    _startPolling() {
223
+        this._stopPolling();
224
+        this._poller = window.setInterval(this._updateSources, UPDATE_INTERVAL);
207
     }
225
     }
208
 
226
 
209
     /**
227
     /**
210
-     * Dispatches an action to hide the DesktopPicker and invokes
211
-     * the passed in callback with a selectedSourceId, if any.
228
+     * Cancels the interval to update DesktopCapturerSources.
212
      *
229
      *
213
-     * @param {string} id - The id of the DesktopCapturerSource to pass into
214
-     * the onSourceChoose callback.
230
+     * @private
215
      * @returns {void}
231
      * @returns {void}
216
      */
232
      */
217
-    _onCloseModal(id = '') {
218
-        this.props.onSourceChoose(id);
219
-        this.props.dispatch(hideDialog());
233
+    _stopPolling() {
234
+        window.clearInterval(this._poller);
235
+        this._poller = null;
220
     }
236
     }
221
 
237
 
222
     /**
238
     /**
223
-     * Configures and renders the tabs for display.
239
+     * Dispatches an action to get currently available DesktopCapturerSources.
224
      *
240
      *
225
-     * @returns {ReactElement}
226
      * @private
241
      * @private
242
+     * @returns {void}
227
      */
243
      */
228
-    _renderTabs() {
229
-        const tabs = tabsToPopulate.map(tabConfig => {
230
-            const type = tabConfig.type;
231
-
232
-            return {
233
-                label: this.props.t(tabConfig.label),
234
-                defaultSelected: tabConfig.isDefault,
235
-                content: <DesktopPickerPane
236
-                    key = { type }
237
-                    onClick = { this._onPreviewClick }
238
-                    onDoubleClick = { this._onCloseModal }
239
-                    selectedSourceId = { this.state.selectedSourceId }
240
-                    sources = { this.props.sources[type] || [] }
241
-                    type = { type } />
242
-            };
243
-        });
244
-
245
-        return <Tabs tabs = { tabs } />;
244
+    _updateSources() {
245
+        this.props.dispatch(obtainDesktopSources(
246
+            TYPES_TO_FETCH,
247
+            {
248
+                THUMBNAIL_SIZE
249
+            }
250
+        ));
246
     }
251
     }
247
 }
252
 }
248
 
253
 
250
  * Maps (parts of) the Redux state to the associated DesktopPicker's props.
255
  * Maps (parts of) the Redux state to the associated DesktopPicker's props.
251
  *
256
  *
252
  * @param {Object} state - Redux state.
257
  * @param {Object} state - Redux state.
253
- * @protected
258
+ * @private
254
  * @returns {{
259
  * @returns {{
255
  *     sources: Object
260
  *     sources: Object
256
  * }}
261
  * }}
257
  */
262
  */
258
-function mapStateToProps(state) {
263
+function _mapStateToProps(state) {
259
     return {
264
     return {
260
-        sources: state['features/desktop-picker/sources']
265
+        sources: state['features/desktop-picker']
261
     };
266
     };
262
 }
267
 }
263
 
268
 
264
-export default translate(connect(mapStateToProps)(DesktopPicker));
269
+export default translate(connect(_mapStateToProps)(DesktopPicker));

+ 23
- 13
react/features/desktop-picker/components/DesktopPickerPane.js 查看文件

1
 import React, { Component } from 'react';
1
 import React, { Component } from 'react';
2
+
2
 import DesktopSourcePreview from './DesktopSourcePreview';
3
 import DesktopSourcePreview from './DesktopSourcePreview';
3
 
4
 
4
 /**
5
 /**
19
         onClick: React.PropTypes.func,
20
         onClick: React.PropTypes.func,
20
 
21
 
21
         /**
22
         /**
22
-         * The handler to be invoked when a DesktopSourcePreview is
23
-         * double clicked.
23
+         * The handler to be invoked when a DesktopSourcePreview is double
24
+         * clicked.
24
          */
25
          */
25
         onDoubleClick: React.PropTypes.func,
26
         onDoubleClick: React.PropTypes.func,
26
 
27
 
47
      * @returns {ReactElement}
48
      * @returns {ReactElement}
48
      */
49
      */
49
     render() {
50
     render() {
50
-        const previews = this.props.sources.map(source =>
51
-            <DesktopSourcePreview
52
-                isSelected = { source.id === this.props.selectedSourceId }
53
-                key = { source.id }
54
-                onClick = { this.props.onClick }
55
-                onDoubleClick = { this.props.onDoubleClick }
56
-                source = { source } />
57
-        );
58
-        const classnames = 'desktop-picker-pane default-scrollbar '
59
-            + `source-type-${this.props.type}`;
51
+        const {
52
+            onClick,
53
+            onDoubleClick,
54
+            selectedSourceId,
55
+            sources,
56
+            type
57
+        } = this.props;
58
+
59
+        const classNames
60
+            = `desktop-picker-pane default-scrollbar source-type-${type}`;
61
+        const previews
62
+            = sources.map(
63
+                source =>
64
+                    <DesktopSourcePreview
65
+                        key = { source.id }
66
+                        onClick = { onClick }
67
+                        onDoubleClick = { onDoubleClick }
68
+                        selected = { source.id === selectedSourceId }
69
+                        source = { source } />);
60
 
70
 
61
         return (
71
         return (
62
-            <div className = { classnames }>
72
+            <div className = { classNames }>
63
                 { previews }
73
                 { previews }
64
             </div>
74
             </div>
65
         );
75
         );

+ 12
- 10
react/features/desktop-picker/components/DesktopSourcePreview.js 查看文件

13
      */
13
      */
14
     static propTypes = {
14
     static propTypes = {
15
         /**
15
         /**
16
-         * If true the 'is-selected' class will be added to the component.
16
+         * The callback to invoke when the component is clicked. The id of
17
+         * the DesktopCapturerSource will be passed in.
17
          */
18
          */
18
-        isSelected: React.PropTypes.bool,
19
+        onClick: React.PropTypes.func,
19
 
20
 
20
         /**
21
         /**
21
-         * The callback to invoke when the component is clicked.
22
-         * The id of the DesktopCapturerSource will be passed in.
22
+         * The callback to invoke when the component is double clicked. The id
23
+         * of the DesktopCapturerSource will be passed in.
23
          */
24
          */
24
-        onClick: React.PropTypes.func,
25
+        onDoubleClick: React.PropTypes.func,
25
 
26
 
26
         /**
27
         /**
27
-         * The callback to invoke when the component is double clicked.
28
-         * The id of the DesktopCapturerSource will be passed in.
28
+         * The indicator which determines whether this DesktopSourcePreview is
29
+         * selected. If true, the 'is-selected' CSS class will be added to the
30
+         * Component.
29
          */
31
          */
30
-        onDoubleClick: React.PropTypes.func,
32
+        selected: React.PropTypes.bool,
31
 
33
 
32
         /**
34
         /**
33
          * The DesktopCapturerSource to display.
35
          * The DesktopCapturerSource to display.
55
      * @returns {ReactElement}
57
      * @returns {ReactElement}
56
      */
58
      */
57
     render() {
59
     render() {
58
-        const isSelectedClass = this.props.isSelected ? 'is-selected' : '';
59
-        const displayClasses = `desktop-picker-source ${isSelectedClass}`;
60
+        const selectedClass = this.props.selected ? 'is-selected' : '';
61
+        const displayClasses = `desktop-picker-source ${selectedClass}`;
60
 
62
 
61
         return (
63
         return (
62
             <div
64
             <div

+ 1
- 1
react/features/desktop-picker/index.js 查看文件

1
-export * from './actionTypes';
2
 export * from './actions';
1
 export * from './actions';
2
+export * from './actionTypes';
3
 export * from './components';
3
 export * from './components';
4
 
4
 
5
 import './reducer';
5
 import './reducer';

+ 17
- 14
react/features/desktop-picker/reducer.js 查看文件

1
 import { ReducerRegistry } from '../base/redux';
1
 import { ReducerRegistry } from '../base/redux';
2
+
2
 import {
3
 import {
3
     RESET_DESKTOP_SOURCES,
4
     RESET_DESKTOP_SOURCES,
4
     UPDATE_DESKTOP_SOURCES
5
     UPDATE_DESKTOP_SOURCES
5
 } from './actionTypes';
6
 } from './actionTypes';
6
 
7
 
7
-const defaultState = {
8
+const DEFAULT_STATE = {
8
     screen: [],
9
     screen: [],
9
     window: []
10
     window: []
10
 };
11
 };
19
  * @returns {Object}
20
  * @returns {Object}
20
  */
21
  */
21
 ReducerRegistry.register(
22
 ReducerRegistry.register(
22
-    'features/desktop-picker/sources',
23
-    (state = defaultState, action) => {
23
+    'features/desktop-picker',
24
+    (state = DEFAULT_STATE, action) => {
24
         switch (action.type) {
25
         switch (action.type) {
25
         case RESET_DESKTOP_SOURCES:
26
         case RESET_DESKTOP_SOURCES:
26
-            return { ...defaultState };
27
+            return { ...DEFAULT_STATE };
28
+
27
         case UPDATE_DESKTOP_SOURCES:
29
         case UPDATE_DESKTOP_SOURCES:
28
-            return seperateSourcesByType(action.sources);
30
+            return _seperateSourcesByType(action.sources);
31
+
29
         default:
32
         default:
30
             return state;
33
             return state;
31
         }
34
         }
32
     });
35
     });
33
 
36
 
34
 /**
37
 /**
35
- * Converts an array of DesktopCapturerSources to an object with types
36
- * for keys and values being an array with sources of the key's type.
38
+ * Converts an array of DesktopCapturerSources to an object with types for keys
39
+ * and values being an array with sources of the key's type.
37
  *
40
  *
38
  * @param {Array} sources - DesktopCapturerSources.
41
  * @param {Array} sources - DesktopCapturerSources.
39
- * @returns {Object} An object with the sources split into seperate arrays
40
- * based on source type.
41
  * @private
42
  * @private
43
+ * @returns {Object} An object with the sources split into seperate arrays based
44
+ * on source type.
42
  */
45
  */
43
-function seperateSourcesByType(sources = []) {
46
+function _seperateSourcesByType(sources = []) {
44
     const sourcesByType = {
47
     const sourcesByType = {
45
         screen: [],
48
         screen: [],
46
         window: []
49
         window: []
47
     };
50
     };
48
 
51
 
49
     sources.forEach(source => {
52
     sources.forEach(source => {
50
-        const sourceIdParts = source.id.split(':');
51
-        const sourceType = sourceIdParts[0];
53
+        const idParts = source.id.split(':');
54
+        const type = idParts[0];
52
 
55
 
53
-        if (sourcesByType[sourceType]) {
54
-            sourcesByType[sourceType].push(source);
56
+        if (sourcesByType[type]) {
57
+            sourcesByType[type].push(source);
55
         }
58
         }
56
     });
59
     });
57
 
60
 

正在加载...
取消
保存