Explorar el Código

Adds base dialog implementation.

j8
damencho hace 8 años
padre
commit
51f0c8a388

+ 3
- 0
package.json Ver fichero

@@ -17,6 +17,9 @@
17 17
   "//": "Callstats.io does not work with recent versions of jsSHA (2.0.1 in particular)",
18 18
   "dependencies": {
19 19
     "@atlassian/aui": "6.0.6",
20
+    "@atlaskit/button": "1.0.3",
21
+    "@atlaskit/button-group": "1.0.0",
22
+    "@atlaskit/modal-dialog": "1.2.4",
20 23
     "async": "0.9.0",
21 24
     "autosize": "1.18.13",
22 25
     "bootstrap": "3.1.1",

+ 22
- 0
react/features/base/dialog/actionTypes.js Ver fichero

@@ -0,0 +1,22 @@
1
+import { Symbol } from '../react';
2
+
3
+/**
4
+ * The type of Redux action which closes a dialog
5
+ *
6
+ * {
7
+ *     type: HIDE_DIALOG
8
+ * }
9
+ */
10
+export const HIDE_DIALOG = Symbol('HIDE_DIALOG');
11
+
12
+/**
13
+ * The type of Redux action which begins a request to open a dialog.
14
+ *
15
+ * {
16
+ *     type: OPEN_DIALOG,
17
+ *     component: React.Component,
18
+ *     props: React.PropTypes.object
19
+ * }
20
+ *
21
+ */
22
+export const OPEN_DIALOG = Symbol('OPEN_DIALOG');

+ 32
- 0
react/features/base/dialog/actions.js Ver fichero

@@ -0,0 +1,32 @@
1
+import {
2
+    HIDE_DIALOG,
3
+    OPEN_DIALOG
4
+} from './actionTypes';
5
+
6
+/**
7
+ * Signals Dialog to close its dialog.
8
+ *
9
+ * @returns {{
10
+ *     type: HIDE_DIALOG
11
+ * }}
12
+ */
13
+export function hideDialog() {
14
+    return {
15
+        type: HIDE_DIALOG
16
+    };
17
+}
18
+
19
+/**
20
+ * Signals Dialog to open dialog.
21
+ *
22
+ * @param {Object} component - The component to display as dialog.
23
+ * @param {Object} componentProps - The properties needed for that component.
24
+ * @returns {Object}
25
+ */
26
+export function openDialog(component, componentProps) {
27
+    return {
28
+        type: OPEN_DIALOG,
29
+        component,
30
+        componentProps
31
+    };
32
+}

+ 110
- 0
react/features/base/dialog/components/AbstractDialog.js Ver fichero

@@ -0,0 +1,110 @@
1
+import React, { Component } from 'react';
2
+
3
+import { hideDialog } from '../actions';
4
+
5
+/**
6
+ * Abstract dialog to display dialogs.
7
+ */
8
+export default class AbstractDialog extends Component {
9
+
10
+    /**
11
+     * Abstract Dialog component's property types.
12
+     *
13
+     * @static
14
+     */
15
+    static propTypes = {
16
+        /**
17
+         * Whether cancel button is disabled. Enabled by default.
18
+         */
19
+        cancelDisabled: React.PropTypes.bool,
20
+
21
+        /**
22
+         * Optional i18n key to change the cancel button title.
23
+         */
24
+        cancelTitleKey: React.PropTypes.string,
25
+
26
+        /**
27
+         * Used to show hide the dialog on cancel.
28
+         */
29
+        dispatch: React.PropTypes.func,
30
+
31
+        /**
32
+         * Is ok button enabled/disabled. Enabled by default.
33
+         */
34
+        okDisabled: React.PropTypes.bool,
35
+
36
+        /**
37
+         * Optional i18n key to change the ok button title.
38
+         */
39
+        okTitleKey: React.PropTypes.string,
40
+
41
+        /**
42
+         * The handler for onCancel event.
43
+         */
44
+        onCancel: React.PropTypes.func,
45
+
46
+        /**
47
+         * The handler for the event when submitting the dialog.
48
+         */
49
+        onSubmit: React.PropTypes.func,
50
+
51
+        /**
52
+         * Used to obtain translations in children classes.
53
+         */
54
+        t: React.PropTypes.func,
55
+
56
+        /**
57
+         * Key to use for showing a title.
58
+         */
59
+        titleKey: React.PropTypes.string
60
+    }
61
+
62
+    /**
63
+     * Initializes a new Dialog instance.
64
+     *
65
+     * @param {Object} props - The read-only properties with which the new
66
+     * instance is to be initialized.
67
+     */
68
+    constructor(props) {
69
+        super(props);
70
+
71
+        this._onCancel = this._onCancel.bind(this);
72
+        this._onSubmit = this._onSubmit.bind(this);
73
+    }
74
+
75
+    /**
76
+     * Dispatches action to hide the dialog.
77
+     *
78
+     * @returns {void}
79
+     */
80
+    _onCancel() {
81
+        let hide = true;
82
+
83
+        if (this.props.onCancel) {
84
+            hide = this.props.onCancel();
85
+        }
86
+
87
+        if (hide) {
88
+            this.props.dispatch(hideDialog());
89
+        }
90
+    }
91
+
92
+    /**
93
+     * Dispatches the action when submitting the dialog.
94
+     *
95
+     * @private
96
+     * @param {string} value - The submitted value if any.
97
+     * @returns {void}
98
+     */
99
+    _onSubmit(value) {
100
+        let hide = true;
101
+
102
+        if (this.props.onSubmit) {
103
+            hide = this.props.onSubmit(value);
104
+        }
105
+
106
+        if (hide) {
107
+            this.props.dispatch(hideDialog());
108
+        }
109
+    }
110
+}

+ 58
- 0
react/features/base/dialog/components/Dialog.native.js Ver fichero

@@ -0,0 +1,58 @@
1
+import React from 'react';
2
+import { connect } from 'react-redux';
3
+import Prompt from 'react-native-prompt';
4
+
5
+import { translate } from '../../i18n';
6
+
7
+import AbstractDialog from './AbstractDialog';
8
+
9
+/**
10
+ * Native dialog using Prompt.
11
+ */
12
+class Dialog extends AbstractDialog {
13
+
14
+    /**
15
+     * Native sialog component's property types.
16
+     *
17
+     * @static
18
+     */
19
+    static propTypes = {
20
+        /**
21
+         * I18n key to put as body title.
22
+         */
23
+        bodyKey: React.PropTypes.string
24
+    }
25
+
26
+    /**
27
+     * Implements React's {@link Component#render()}.
28
+     *
29
+     * @inheritdoc
30
+     * @returns {ReactElement}
31
+     */
32
+    render() {
33
+        const {
34
+            cancelDisabled,
35
+            cancelTitleKey,
36
+            bodyKey,
37
+            okDisabled,
38
+            okTitleKey,
39
+            t,
40
+            titleKey
41
+        } = this.props;
42
+
43
+        return (
44
+            <Prompt
45
+                cancelText = { cancelDisabled
46
+                    ? undefined : t(cancelTitleKey || 'dialog.Cancel') }
47
+                onCancel = { this._onCancel }
48
+                onSubmit = { this._onSubmit }
49
+                placeholder = { t(bodyKey) }
50
+                submitText = { okDisabled
51
+                    ? undefined : t(okTitleKey || 'dialog.Ok') }
52
+                title = { t(titleKey) }
53
+                visible = { true } />
54
+        );
55
+    }
56
+}
57
+
58
+export default translate(connect()(Dialog));

+ 159
- 0
react/features/base/dialog/components/Dialog.web.js Ver fichero

@@ -0,0 +1,159 @@
1
+import AKButton from '@atlaskit/button';
2
+import AKButtonGroup from '@atlaskit/button-group';
3
+import ModalDialog from '@atlaskit/modal-dialog';
4
+import React from 'react';
5
+import { connect } from 'react-redux';
6
+
7
+import { translate } from '../../i18n';
8
+
9
+import AbstractDialog from './AbstractDialog';
10
+
11
+/**
12
+ * Web dialog that uses atlaskit modal-dialog to display dialogs.
13
+ */
14
+class Dialog extends AbstractDialog {
15
+
16
+    /**
17
+     * Web dialog component's property types.
18
+     *
19
+     * @static
20
+     */
21
+    static propTypes = {
22
+        /**
23
+         * This is the body of the dialog, the component children.
24
+         */
25
+        children: React.PropTypes.node,
26
+
27
+        /**
28
+         * Whether the dialog is modal. This means clicking on the blanket will
29
+         * leave the dialog open. No cancel button.
30
+         */
31
+        isModal: React.PropTypes.bool,
32
+
33
+        /**
34
+         * Width of the dialog, can be:
35
+         * - 'small' (400px), 'medium' (600px), 'large' (800px),
36
+         * 'x-large' (968px)
37
+         * - integer value for pixel width
38
+         * - string value for percentage
39
+         */
40
+        width: React.PropTypes.string
41
+    }
42
+
43
+    /**
44
+     * Implements React's {@link Component#render()}.
45
+     *
46
+     * @inheritdoc
47
+     * @returns {ReactElement}
48
+     */
49
+    render() {
50
+        return (
51
+            <ModalDialog
52
+                footer = { this._renderFooter() }
53
+                header = { this._renderHeader() }
54
+                isOpen = { true }
55
+                onDialogDismissed = { this._onCancel }
56
+                width = { this.props.width || 'medium' }>
57
+                <div>
58
+                    <form
59
+                        id = 'modal-dialog-form'
60
+                        onSubmit = { this._onSubmit }>
61
+                        { this.props.children }
62
+                    </form>
63
+                </div>
64
+            </ModalDialog>);
65
+    }
66
+
67
+    /**
68
+     * Render cancel button.
69
+     *
70
+     * @returns {*} The cancel button if enabled and dialog is not modal.
71
+     * @private
72
+     */
73
+    _renderCancelButton() {
74
+        if (this.props.cancelDisabled || this.props.isModal) {
75
+            return null;
76
+        }
77
+
78
+        return (
79
+            <AKButton
80
+                appearance = 'subtle'
81
+                id = 'modal-dialog-cancel-button'
82
+                onClick = { this._onCancel }>
83
+                { this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') }
84
+            </AKButton>
85
+        );
86
+    }
87
+
88
+    /**
89
+     * Render component in dialog footer.
90
+     *
91
+     * @returns {ReactElement}
92
+     * @private
93
+     */
94
+    _renderFooter() {
95
+        return (
96
+            <footer>
97
+                <AKButtonGroup>
98
+                    { this._renderCancelButton() }
99
+                    { this._renderOKButton() }
100
+                </AKButtonGroup>
101
+            </footer>
102
+        );
103
+    }
104
+
105
+    /**
106
+     * Render component in dialog header.
107
+     *
108
+     * @returns {ReactElement}
109
+     * @private
110
+     */
111
+    _renderHeader() {
112
+        const { t } = this.props;
113
+
114
+        return (
115
+            <header>
116
+                <h2>
117
+                    { t(this.props.titleKey) }
118
+                </h2>
119
+            </header>
120
+        );
121
+    }
122
+
123
+    /**
124
+     * Render ok button.
125
+     *
126
+     * @returns {*} The ok button if enabled.
127
+     * @private
128
+     */
129
+    _renderOKButton() {
130
+        if (this.props.submitDisabled) {
131
+            return null;
132
+        }
133
+
134
+        return (
135
+            <AKButton
136
+                appearance = 'primary'
137
+                form = 'modal-dialog-form'
138
+                id = 'modal-dialog-ok-button'
139
+                onClick = { this._onSubmit }>
140
+                { this.props.t(this.props.okTitleKey || 'dialog.Ok') }
141
+            </AKButton>
142
+        );
143
+    }
144
+
145
+    /**
146
+     * Dispatches action to hide the dialog.
147
+     *
148
+     * @returns {void}
149
+     */
150
+    _onCancel() {
151
+        if (this.props.isModal) {
152
+            return;
153
+        }
154
+
155
+        super._onCancel();
156
+    }
157
+}
158
+
159
+export default translate(connect()(Dialog));

+ 61
- 0
react/features/base/dialog/components/DialogContainer.js Ver fichero

@@ -0,0 +1,61 @@
1
+import React, { Component } from 'react';
2
+import { connect } from 'react-redux';
3
+
4
+/**
5
+ * Implements a DialogContainer that will be responsible for
6
+ * showing all dialogs. We will need a separate container so we can handle
7
+ * multiple dialogs, showing them simultaneously or queueing them.
8
+ */
9
+export class DialogContainer extends Component {
10
+
11
+    /**
12
+     * DialogContainer component's property types.
13
+     *
14
+     * @static
15
+     */
16
+    static propTypes = {
17
+        /**
18
+         * The component to render.
19
+         */
20
+        _component: React.PropTypes.func,
21
+
22
+        /**
23
+         * The props to pass to the component that will be rendered.
24
+         */
25
+        _componentProps: React.PropTypes.object
26
+    }
27
+
28
+    /**
29
+     * Implements React's {@link Component#render()}.
30
+     *
31
+     * @inheritdoc
32
+     * @returns {ReactElement}
33
+     */
34
+    render() {
35
+        if (!this.props._component) {
36
+            return null;
37
+        }
38
+
39
+        return React.createElement(
40
+            this.props._component, this.props._componentProps);
41
+    }
42
+}
43
+
44
+/**
45
+ * Maps (parts of) the Redux state to the associated Dialog's props.
46
+ *
47
+ * @param {Object} state - The Redux state.
48
+ * @private
49
+ * @returns {{
50
+ *     _component: React.Component,
51
+ *     _props: React.PropTypes.object
52
+ * }}
53
+ */
54
+function _mapStateToProps(state) {
55
+    return {
56
+        _component: state['features/base/dialog'].component,
57
+        _componentProps: state['features/base/dialog'].componentProps
58
+    };
59
+}
60
+
61
+export default connect(_mapStateToProps)(DialogContainer);

+ 2
- 0
react/features/base/dialog/components/index.js Ver fichero

@@ -0,0 +1,2 @@
1
+export { default as DialogContainer } from './DialogContainer';
2
+export { default as Dialog } from './Dialog';

+ 4
- 0
react/features/base/dialog/index.js Ver fichero

@@ -0,0 +1,4 @@
1
+export * from './actions';
2
+export * from './components';
3
+
4
+import './reducer';

+ 31
- 0
react/features/base/dialog/reducer.js Ver fichero

@@ -0,0 +1,31 @@
1
+import { ReducerRegistry, setStateProperties } from '../redux';
2
+
3
+import {
4
+    HIDE_DIALOG,
5
+    OPEN_DIALOG
6
+} from './actionTypes';
7
+
8
+/**
9
+ * Listen for actions which show or hide dialogs.
10
+ *
11
+ * @param {Object[]} state - Current state.
12
+ * @param {Object} action - Action object.
13
+ * @param {string} action.type - Type of action.
14
+ * @returns {{}}
15
+ */
16
+ReducerRegistry.register('features/base/dialog', (state = {}, action) => {
17
+    switch (action.type) {
18
+    case HIDE_DIALOG:
19
+        return setStateProperties(state, {
20
+            component: undefined,
21
+            componentProps: undefined
22
+        });
23
+    case OPEN_DIALOG:
24
+        return setStateProperties(state, {
25
+            component: action.component,
26
+            componentProps: action.componentProps
27
+        });
28
+    }
29
+
30
+    return state;
31
+});

+ 3
- 0
react/features/conference/components/Conference.native.js Ver fichero

@@ -2,6 +2,7 @@ import React, { Component } from 'react';
2 2
 import { connect as reactReduxConnect } from 'react-redux';
3 3
 
4 4
 import { connect, disconnect } from '../../base/connection';
5
+import { DialogContainer } from '../../base/dialog';
5 6
 import { Container } from '../../base/react';
6 7
 import { FilmStrip } from '../../film-strip';
7 8
 import { LargeVideo } from '../../large-video';
@@ -125,6 +126,8 @@ class Conference extends Component {
125 126
                 <Toolbar visible = { toolbarVisible } />
126 127
                 <FilmStrip visible = { !toolbarVisible } />
127 128
 
129
+                <DialogContainer />
130
+
128 131
                 {
129 132
                     this._renderPrompt()
130 133
                 }

+ 2
- 1
react/features/conference/components/Conference.web.js Ver fichero

@@ -4,6 +4,7 @@ import React, { Component } from 'react';
4 4
 import { connect as reactReduxConnect } from 'react-redux';
5 5
 
6 6
 import { connect, disconnect } from '../../base/connection';
7
+import { DialogContainer } from '../../base/dialog';
7 8
 import { Watermarks } from '../../base/react';
8 9
 import { FeedbackButton } from '../../feedback';
9 10
 import { OverlayContainer } from '../../overlay';
@@ -170,7 +171,7 @@ class Conference extends Component {
170 171
                         </div>
171 172
                     </div>
172 173
                 </div>
173
-
174
+                <DialogContainer />
174 175
                 <OverlayContainer />
175 176
                 <HideNotificationBarStyle />
176 177
             </div>

Loading…
Cancelar
Guardar