Przeglądaj źródła

Handles Enter key to submit dialogs.

If there is no focused node inside the dialog we focus any of the available buttons, submit button is first.
j8
damencho 8 lat temu
rodzic
commit
8e3dfcf0d0

+ 122
- 17
react/features/base/dialog/components/StatelessDialog.web.js Wyświetl plik

@@ -7,6 +7,18 @@ import { translate } from '../../i18n';
7 7
 
8 8
 import { DIALOG_PROP_TYPES } from '../constants';
9 9
 
10
+/**
11
+ * The ID to be used for the cancel button if enabled.
12
+ * @type {string}
13
+ */
14
+const CANCEL_BUTTON_ID = 'modal-dialog-cancel-button';
15
+
16
+/**
17
+ * The ID to be used for the ok button if enabled.
18
+ * @type {string}
19
+ */
20
+const OK_BUTTON_ID = 'modal-dialog-ok-button';
21
+
10 22
 /**
11 23
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
12 24
  */
@@ -63,7 +75,34 @@ class StatelessDialog extends Component {
63 75
         // Bind event handlers so they are only bound once for every instance.
64 76
         this._onCancel = this._onCancel.bind(this);
65 77
         this._onDialogDismissed = this._onDialogDismissed.bind(this);
78
+        this._onKeyDown = this._onKeyDown.bind(this);
66 79
         this._onSubmit = this._onSubmit.bind(this);
80
+        this._setDialogElement = this._setDialogElement.bind(this);
81
+    }
82
+
83
+    /**
84
+     * React Component method that executes once component is mounted.
85
+     *
86
+     * @inheritdoc
87
+     */
88
+    componentDidMount() {
89
+        this._updateButtonFocus();
90
+    }
91
+
92
+    /**
93
+     * React Component method that executes once component is updated.
94
+     *
95
+     * @param {Object} prevProps - The previous properties, before the update.
96
+     * @returns {void}
97
+     */
98
+    componentDidUpdate(prevProps) {
99
+        // if there is an update in any of the buttons enable/disable props
100
+        // update the focus if needed
101
+        if (prevProps.okDisabled !== this.props.okDisabled
102
+            || prevProps.cancelDisabled !== this.props.cancelDisabled
103
+            || prevProps.submitDisabled !== this.props.submitDisabled) {
104
+            this._updateButtonFocus();
105
+        }
67 106
     }
68 107
 
69 108
     /**
@@ -74,21 +113,25 @@ class StatelessDialog extends Component {
74 113
      */
75 114
     render() {
76 115
         return (
77
-            <ModalDialog
78
-                footer = { this._renderFooter() }
79
-                header = { this._renderHeader() }
80
-                isOpen = { true }
81
-                onDialogDismissed = { this._onDialogDismissed }
82
-                width = { this.props.width || 'medium' }>
83
-                <div>
84
-                    <form
85
-                        className = 'modal-dialog-form'
86
-                        id = 'modal-dialog-form'
87
-                        onSubmit = { this._onSubmit }>
88
-                        { this.props.children }
89
-                    </form>
90
-                </div>
91
-            </ModalDialog>
116
+            <div
117
+                onKeyDown = { this._onKeyDown }
118
+                ref = { this._setDialogElement }>
119
+                <ModalDialog
120
+                    footer = { this._renderFooter() }
121
+                    header = { this._renderHeader() }
122
+                    isOpen = { true }
123
+                    onDialogDismissed = { this._onDialogDismissed }
124
+                    width = { this.props.width || 'medium' }>
125
+                    <div>
126
+                        <form
127
+                            className = 'modal-dialog-form'
128
+                            id = 'modal-dialog-form'
129
+                            onSubmit = { this._onSubmit }>
130
+                            { this.props.children }
131
+                        </form>
132
+                    </div>
133
+                </ModalDialog>
134
+            </div>
92 135
         );
93 136
     }
94 137
 
@@ -139,7 +182,7 @@ class StatelessDialog extends Component {
139 182
         return (
140 183
             <AKButton
141 184
                 appearance = 'subtle'
142
-                id = 'modal-dialog-cancel-button'
185
+                id = { CANCEL_BUTTON_ID }
143 186
                 onClick = { this._onCancel }>
144 187
                 { this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') }
145 188
             </AKButton>
@@ -196,13 +239,75 @@ class StatelessDialog extends Component {
196 239
             <AKButton
197 240
                 appearance = 'primary'
198 241
                 form = 'modal-dialog-form'
199
-                id = 'modal-dialog-ok-button'
242
+                id = { OK_BUTTON_ID }
200 243
                 isDisabled = { this.props.okDisabled }
201 244
                 onClick = { this._onSubmit }>
202 245
                 { this.props.t(this.props.okTitleKey || 'dialog.Ok') }
203 246
             </AKButton>
204 247
         );
205 248
     }
249
+
250
+    /**
251
+     * Sets the instance variable for the div containing the component's dialog
252
+     * element so it can be accessed directly.
253
+     *
254
+     * @param {Object} element - The DOM element for the component's dialog.
255
+     * @private
256
+     * @returns {void}
257
+     */
258
+    _setDialogElement(element) {
259
+        this._dialogElement = element;
260
+    }
261
+
262
+    /**
263
+     * Handles 'Enter' key in the dialog to submit/hide dialog depending on
264
+     * the available buttons and their disabled state.
265
+     *
266
+     * @param {Object} event - the key event.
267
+     * @private
268
+     * @returns {void}
269
+     */
270
+    _onKeyDown(event) {
271
+        if (event.key === 'Enter') {
272
+            if (this.props.submitDisabled && !this.props.cancelDisabled) {
273
+                this._onCancel();
274
+            } else if (!this.props.okDisabled) {
275
+                this._onSubmit();
276
+            }
277
+        }
278
+    }
279
+
280
+    /**
281
+     * Updates focused button, if we have a reference to the dialog element.
282
+     * Focus on available button if there is no focus already.
283
+     *
284
+     * @private
285
+     * @returns {void}
286
+     */
287
+    _updateButtonFocus() {
288
+        if (this._dialogElement) {
289
+
290
+            // if we have a focused element inside the dialog, skip changing
291
+            // the focus
292
+            if (this._dialogElement.contains(document.activeElement)) {
293
+                return;
294
+            }
295
+
296
+            let buttonToFocus;
297
+
298
+            if (this.props.submitDisabled) {
299
+                buttonToFocus = this._dialogElement
300
+                    .querySelector(`[id=${CANCEL_BUTTON_ID}]`);
301
+            } else if (!this.props.okDisabled) {
302
+                buttonToFocus = this._dialogElement
303
+                    .querySelector(`[id=${OK_BUTTON_ID}]`);
304
+            }
305
+
306
+            if (buttonToFocus) {
307
+                buttonToFocus.focus();
308
+            }
309
+        }
310
+    }
206 311
 }
207 312
 
208 313
 export default translate(StatelessDialog);

Ładowanie…
Anuluj
Zapisz