diff --git a/react/features/base/buttons/CopyButton.js b/react/features/base/buttons/CopyButton.js index c8a6256dd..52117077d 100644 --- a/react/features/base/buttons/CopyButton.js +++ b/react/features/base/buttons/CopyButton.js @@ -49,9 +49,12 @@ function CopyButton({ className, displayedText, textToCopy, textOnHover, textOnC * * @returns {void} */ - function onClick() { + async function onClick() { setIsHovered(false); - if (copyText(textToCopy)) { + + const isCopied = await copyText(textToCopy); + + if (isCopied) { setIsClicked(true); setTimeout(() => { diff --git a/react/features/base/premeeting/components/web/CopyMeetingUrl.js b/react/features/base/premeeting/components/web/CopyMeetingUrl.js index c434416cb..5da7af3bb 100644 --- a/react/features/base/premeeting/components/web/CopyMeetingUrl.js +++ b/react/features/base/premeeting/components/web/CopyMeetingUrl.js @@ -7,7 +7,6 @@ import { translate } from '../../../i18n'; import { Icon, IconCopy, IconCheck } from '../../../icons'; import { connect } from '../../../redux'; import { copyText, getDecodedURI } from '../../../util'; -import logger from '../../logger'; type Props = { @@ -75,8 +74,8 @@ class CopyMeetingUrl extends Component { * * @returns {void} */ - _copyUrl() { - const success = copyText(this.props.url); + async _copyUrl() { + const success = await copyText(this.props.url); if (success) { this._showLinkCopied(); @@ -152,15 +151,13 @@ class CopyMeetingUrl extends Component { * @private * @returns {void} */ - _copyUrlAutomatically() { - navigator.clipboard.writeText(this.props.url) - .then(() => { - this._showLinkCopied(); - window.setTimeout(this._hideLinkCopied, COPY_TIMEOUT); - }) - .catch(e => { - logger.error(e); - }); + async _copyUrlAutomatically() { + const isCopied = await copyText(this.props.url); + + if (isCopied) { + this._showLinkCopied(); + window.setTimeout(this._hideLinkCopied, COPY_TIMEOUT); + } } /** diff --git a/react/features/base/util/helpers.js b/react/features/base/util/helpers.js index 0408c6409..9ed6e56f8 100644 --- a/react/features/base/util/helpers.js +++ b/react/features/base/util/helpers.js @@ -29,18 +29,36 @@ export function assignIfDefined(target: Object, source: Object) { * Returns true if the action succeeds. * * @param {string} textToCopy - Text to be copied. - * @returns {boolean} + * @returns {Promise} */ export async function copyText(textToCopy: string) { - let result; - try { - result = await navigator.clipboard.writeText(textToCopy); - } catch (err) { - result = false; - } + await navigator.clipboard.writeText(textToCopy); - return result; + return true; + } catch (clipboardAPIError) { // The Clipboard API is not supported. + let fakeTextArea = document.createElement('textarea'); + + // $FlowFixMe + fakeTextArea = document.body.appendChild(fakeTextArea); + fakeTextArea.value = textToCopy; + fakeTextArea.focus(); + fakeTextArea.select(); + + let result; + + try { + result = document.execCommand('copy'); + } catch (error) { + result = false; + } + + // $FlowFixMe + document.body.removeChild(fakeTextArea); + + + return result; + } } /** diff --git a/react/features/invite/components/add-people-dialog/web/LiveStreamSection.js b/react/features/invite/components/add-people-dialog/web/LiveStreamSection.js index f53573322..383eb0a57 100644 --- a/react/features/invite/components/add-people-dialog/web/LiveStreamSection.js +++ b/react/features/invite/components/add-people-dialog/web/LiveStreamSection.js @@ -34,9 +34,12 @@ function LiveStreamSection({ liveStreamViewURL, t }: Props) { * * @returns {void} */ - function onClick() { + async function onClick() { setIsHovered(false); - if (copyText(liveStreamViewURL)) { + + const isCopied = copyText(liveStreamViewURL); + + if (isCopied) { setIsClicked(true); setTimeout(() => {