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