Quellcode durchsuchen

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 vor 8 Jahren
Ursprung
Commit
8e3dfcf0d0
1 geänderte Dateien mit 122 neuen und 17 gelöschten Zeilen
  1. 122
    17
      react/features/base/dialog/components/StatelessDialog.web.js

+ 122
- 17
react/features/base/dialog/components/StatelessDialog.web.js Datei anzeigen

7
 
7
 
8
 import { DIALOG_PROP_TYPES } from '../constants';
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
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
23
  * Web dialog that uses atlaskit modal-dialog to display dialogs.
12
  */
24
  */
63
         // Bind event handlers so they are only bound once for every instance.
75
         // Bind event handlers so they are only bound once for every instance.
64
         this._onCancel = this._onCancel.bind(this);
76
         this._onCancel = this._onCancel.bind(this);
65
         this._onDialogDismissed = this._onDialogDismissed.bind(this);
77
         this._onDialogDismissed = this._onDialogDismissed.bind(this);
78
+        this._onKeyDown = this._onKeyDown.bind(this);
66
         this._onSubmit = this._onSubmit.bind(this);
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
      */
113
      */
75
     render() {
114
     render() {
76
         return (
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
         return (
182
         return (
140
             <AKButton
183
             <AKButton
141
                 appearance = 'subtle'
184
                 appearance = 'subtle'
142
-                id = 'modal-dialog-cancel-button'
185
+                id = { CANCEL_BUTTON_ID }
143
                 onClick = { this._onCancel }>
186
                 onClick = { this._onCancel }>
144
                 { this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') }
187
                 { this.props.t(this.props.cancelTitleKey || 'dialog.Cancel') }
145
             </AKButton>
188
             </AKButton>
196
             <AKButton
239
             <AKButton
197
                 appearance = 'primary'
240
                 appearance = 'primary'
198
                 form = 'modal-dialog-form'
241
                 form = 'modal-dialog-form'
199
-                id = 'modal-dialog-ok-button'
242
+                id = { OK_BUTTON_ID }
200
                 isDisabled = { this.props.okDisabled }
243
                 isDisabled = { this.props.okDisabled }
201
                 onClick = { this._onSubmit }>
244
                 onClick = { this._onSubmit }>
202
                 { this.props.t(this.props.okTitleKey || 'dialog.Ok') }
245
                 { this.props.t(this.props.okTitleKey || 'dialog.Ok') }
203
             </AKButton>
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
 export default translate(StatelessDialog);
313
 export default translate(StatelessDialog);

Laden…
Abbrechen
Speichern