|
@@ -7,7 +7,7 @@ import { setPassword } from '../../../../base/conference';
|
7
|
7
|
import { getInviteURL } from '../../../../base/connection';
|
8
|
8
|
import { Dialog } from '../../../../base/dialog';
|
9
|
9
|
import { translate } from '../../../../base/i18n';
|
10
|
|
-import { Icon, IconInfo } from '../../../../base/icons';
|
|
10
|
+import { Icon, IconInfo, IconCopy } from '../../../../base/icons';
|
11
|
11
|
import { connect } from '../../../../base/redux';
|
12
|
12
|
import {
|
13
|
13
|
isLocalParticipantModerator,
|
|
@@ -136,6 +136,7 @@ type State = {
|
136
|
136
|
*/
|
137
|
137
|
class InfoDialog extends Component<Props, State> {
|
138
|
138
|
_copyElement: ?Object;
|
|
139
|
+ _copyUrlElement: ?Object;
|
139
|
140
|
|
140
|
141
|
/**
|
141
|
142
|
* Implements React's {@link Component#getDerivedStateFromProps()}.
|
|
@@ -197,12 +198,14 @@ class InfoDialog extends Component<Props, State> {
|
197
|
198
|
|
198
|
199
|
// Bind event handlers so they are only bound once for every instance.
|
199
|
200
|
this._onClickURLText = this._onClickURLText.bind(this);
|
200
|
|
- this._onCopyInviteURL = this._onCopyInviteURL.bind(this);
|
|
201
|
+ this._onCopyInviteInfo = this._onCopyInviteInfo.bind(this);
|
|
202
|
+ this._onCopyInviteUrl = this._onCopyInviteUrl.bind(this);
|
201
|
203
|
this._onPasswordRemove = this._onPasswordRemove.bind(this);
|
202
|
204
|
this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
|
203
|
205
|
this._onTogglePasswordEditState
|
204
|
206
|
= this._onTogglePasswordEditState.bind(this);
|
205
|
207
|
this._setCopyElement = this._setCopyElement.bind(this);
|
|
208
|
+ this._setCopyUrlElement = this._setCopyUrlElement.bind(this);
|
206
|
209
|
}
|
207
|
210
|
|
208
|
211
|
/**
|
|
@@ -239,12 +242,18 @@ class InfoDialog extends Component<Props, State> {
|
239
|
242
|
<span className = 'spacer'> </span>
|
240
|
243
|
<span className = 'info-value'>
|
241
|
244
|
<a
|
242
|
|
- className = 'info-dialog-url-text'
|
|
245
|
+ className = 'info-dialog-url-text info-dialog-url-text-unselectable'
|
243
|
246
|
href = { this.props._inviteURL }
|
244
|
247
|
onClick = { this._onClickURLText } >
|
245
|
248
|
{ decodeURI(this._getURLToDisplay()) }
|
246
|
249
|
</a>
|
247
|
250
|
</span>
|
|
251
|
+ <span className = 'info-dialog-url-icon'>
|
|
252
|
+ <Icon
|
|
253
|
+ onClick = { this._onCopyInviteUrl }
|
|
254
|
+ size = { 18 }
|
|
255
|
+ src = { IconCopy } />
|
|
256
|
+ </span>
|
248
|
257
|
</div>
|
249
|
258
|
<div className = 'info-dialog-dial-in'>
|
250
|
259
|
{ this._renderDialInDisplay() }
|
|
@@ -262,7 +271,7 @@ class InfoDialog extends Component<Props, State> {
|
262
|
271
|
<div className = 'info-dialog-action-link'>
|
263
|
272
|
<a
|
264
|
273
|
className = 'info-copy'
|
265
|
|
- onClick = { this._onCopyInviteURL }>
|
|
274
|
+ onClick = { this._onCopyInviteInfo }>
|
266
|
275
|
{ t('dialog.copy') }
|
267
|
276
|
</a>
|
268
|
277
|
</div>
|
|
@@ -275,6 +284,12 @@ class InfoDialog extends Component<Props, State> {
|
275
|
284
|
ref = { this._setCopyElement }
|
276
|
285
|
tabIndex = '-1'
|
277
|
286
|
value = { this._getTextToCopy() } />
|
|
287
|
+ <textarea
|
|
288
|
+ className = 'info-dialog-copy-element'
|
|
289
|
+ readOnly = { true }
|
|
290
|
+ ref = { this._setCopyUrlElement }
|
|
291
|
+ tabIndex = '-1'
|
|
292
|
+ value = { this.props._inviteURL } />
|
278
|
293
|
</div>
|
279
|
294
|
);
|
280
|
295
|
|
|
@@ -365,7 +380,7 @@ class InfoDialog extends Component<Props, State> {
|
365
|
380
|
event.preventDefault();
|
366
|
381
|
}
|
367
|
382
|
|
368
|
|
- _onCopyInviteURL: () => void;
|
|
383
|
+ _onCopyInviteInfo: () => void;
|
369
|
384
|
|
370
|
385
|
/**
|
371
|
386
|
* Callback invoked to copy the contents of {@code this._copyElement} to the
|
|
@@ -374,7 +389,7 @@ class InfoDialog extends Component<Props, State> {
|
374
|
389
|
* @private
|
375
|
390
|
* @returns {void}
|
376
|
391
|
*/
|
377
|
|
- _onCopyInviteURL() {
|
|
392
|
+ _onCopyInviteInfo() {
|
378
|
393
|
try {
|
379
|
394
|
if (!this._copyElement) {
|
380
|
395
|
throw new Error('No element to copy from.');
|
|
@@ -388,6 +403,28 @@ class InfoDialog extends Component<Props, State> {
|
388
|
403
|
}
|
389
|
404
|
}
|
390
|
405
|
|
|
406
|
+ _onCopyInviteUrl: () => void;
|
|
407
|
+
|
|
408
|
+ /**
|
|
409
|
+ * Callback invoked to copy the contents of {@code this._copyUrlElement} to the clipboard.
|
|
410
|
+ *
|
|
411
|
+ * @private
|
|
412
|
+ * @returns {void}
|
|
413
|
+ */
|
|
414
|
+ _onCopyInviteUrl() {
|
|
415
|
+ try {
|
|
416
|
+ if (!this._copyUrlElement) {
|
|
417
|
+ throw new Error('No element to copy from.');
|
|
418
|
+ }
|
|
419
|
+
|
|
420
|
+ this._copyUrlElement && this._copyUrlElement.select();
|
|
421
|
+ document.execCommand('copy');
|
|
422
|
+ this._copyUrlElement && this._copyUrlElement.blur();
|
|
423
|
+ } catch (err) {
|
|
424
|
+ logger.error('error when copying the text', err);
|
|
425
|
+ }
|
|
426
|
+ }
|
|
427
|
+
|
391
|
428
|
_onPasswordRemove: () => void;
|
392
|
429
|
|
393
|
430
|
/**
|
|
@@ -565,6 +602,21 @@ class InfoDialog extends Component<Props, State> {
|
565
|
602
|
_setCopyElement(element: Object) {
|
566
|
603
|
this._copyElement = element;
|
567
|
604
|
}
|
|
605
|
+
|
|
606
|
+ _setCopyUrlElement: () => void;
|
|
607
|
+
|
|
608
|
+ /**
|
|
609
|
+ * Sets the internal reference to the DOM/HTML element backing the React
|
|
610
|
+ * {@code Component} input.
|
|
611
|
+ *
|
|
612
|
+ * @param {HTMLInputElement} element - The DOM/HTML element for this
|
|
613
|
+ * {@code Component}'s input.
|
|
614
|
+ * @private
|
|
615
|
+ * @returns {void}
|
|
616
|
+ */
|
|
617
|
+ _setCopyUrlElement(element: Object) {
|
|
618
|
+ this._copyUrlElement = element;
|
|
619
|
+ }
|
568
|
620
|
}
|
569
|
621
|
|
570
|
622
|
/**
|