ソースを参照

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年前
コミット
8e3dfcf0d0
1個のファイルの変更122行の追加17行の削除
  1. 122
    17
      react/features/base/dialog/components/StatelessDialog.web.js

+ 122
- 17
react/features/base/dialog/components/StatelessDialog.web.js ファイルの表示

@@ -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);

読み込み中…
キャンセル
保存