@@ -373,7 +363,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
onChange={this._onPassPhraseConfirmChange}
value={this.state.passPhraseConfirm}
className="mx_CreateKeyBackupDialog_passPhraseInput"
- placeholder={_t("Repeat your passphrase...")}
+ placeholder={_t("Repeat your recovery passphrase...")}
autoFocus={true}
/>
@@ -393,7 +383,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
return
{_t(
"Your recovery key is a safety net - you can use it to restore " +
- "access to your encrypted messages if you forget your passphrase.",
+ "access to your encrypted messages if you forget your recovery passphrase.",
)}
{_t(
"Keep a copy of it somewhere secure, like a password manager or even a safe.",
@@ -487,9 +477,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
_titleForPhase(phase) {
switch (phase) {
case PHASE_PASSPHRASE:
- return _t('Secure your backup with a passphrase');
+ return _t('Secure your backup with a recovery passphrase');
case PHASE_PASSPHRASE_CONFIRM:
- return _t('Confirm your passphrase');
+ return _t('Confirm your recovery passphrase');
case PHASE_OPTOUT_CONFIRM:
return _t('Warning!');
case PHASE_SHOWKEY:
diff --git a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
index 6588ff5191..9e2264a960 100644
--- a/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
+++ b/src/async-components/views/dialogs/keybackup/NewRecoveryMethodDialog.js
@@ -57,8 +57,7 @@ export default class NewRecoveryMethodDialog extends React.PureComponent {
;
const newMethodDetected =
{_t(
- "A new recovery passphrase and key for Secure " +
- "Messages have been detected.",
+ "A new recovery passphrase and key for Secure Messages have been detected.",
)}
;
const hackWarning =
{_t(
diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
index d63db617d5..0cc145fd96 100644
--- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
+++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js
@@ -24,6 +24,7 @@ import FileSaver from 'file-saver';
import { _t } from '../../../../languageHandler';
import Modal from '../../../../Modal';
import { promptForBackupPassphrase } from '../../../../CrossSigningManager';
+import {copyNode} from "../../../../utils/strings";
const PHASE_LOADING = 0;
const PHASE_MIGRATE = 1;
@@ -38,16 +39,6 @@ const PHASE_CONFIRM_SKIP = 8;
const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
const PASSPHRASE_FEEDBACK_DELAY = 500; // How long after keystroke to offer passphrase feedback, ms.
-// XXX: copied from ShareDialog: factor out into utils
-function selectText(target) {
- const range = document.createRange();
- range.selectNodeContents(target);
-
- const selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(range);
-}
-
/*
* Walks the user through the process of creating a passphrase to guard Secure
* Secret Storage in account data.
@@ -169,8 +160,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
}
_onCopyClick = () => {
- selectText(this._recoveryKeyNode);
- const successful = document.execCommand('copy');
+ const successful = copyNode(this._recoveryKeyNode);
if (successful) {
this.setState({
copied: true,
@@ -472,7 +462,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
let helpText;
if (this.state.zxcvbnResult) {
if (this.state.zxcvbnResult.score >= PASSWORD_MIN_SCORE) {
- helpText = _t("Great! This passphrase looks strong enough.");
+ helpText = _t("Great! This recovery passphrase looks strong enough.");
} else {
// We take the warning from zxcvbn or failing that, the first
// suggestion. In practice The first is generally the most relevant
@@ -497,12 +487,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
return
;
@@ -291,7 +291,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
title = _t("Incorrect recovery passphrase");
content =
;
diff --git a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
index e3a7d7f532..7d7edffcbf 100644
--- a/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
+++ b/src/components/views/dialogs/secretstorage/AccessSecretStorageDialog.js
@@ -119,14 +119,14 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
if (hasPassphrase && !this.state.forceRecoveryKey) {
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
- title = _t("Enter secret storage passphrase");
+ title = _t("Enter recovery passphrase");
let keyStatus;
if (this.state.keyMatches === false) {
keyStatus =
{"\uD83D\uDC4E "}{_t(
- "Unable to access secret storage. Please verify that you " +
- "entered the correct passphrase.",
+ "Unable to access secret storage. " +
+ "Please verify that you entered the correct recovery passphrase.",
)}
;
} else {
@@ -135,13 +135,12 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
content =
;
} else {
- title = _t("Enter secret storage recovery key");
+ title = _t("Enter recovery key");
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -193,8 +192,8 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
} else if (this.state.keyMatches === false) {
keyStatus =
{"\uD83D\uDC4E "}{_t(
- "Unable to access secret storage. Please verify that you " +
- "entered the correct recovery key.",
+ "Unable to access secret storage. " +
+ "Please verify that you entered the correct recovery key.",
)}
;
} else if (this.state.recoveryKeyValid) {
@@ -209,8 +208,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
content =
{_t(
- "Warning : You should only access secret storage " +
- "from a trusted computer.", {},
+ "Warning : You should only do this on a trusted computer.", {},
{ b: sub => {sub} },
)}
{_t(
diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js
index 27514d0e23..882e331675 100644
--- a/src/components/views/messages/TextualBody.js
+++ b/src/components/views/messages/TextualBody.js
@@ -34,6 +34,7 @@ import {pillifyLinks, unmountPills} from '../../../utils/pillify';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import {isPermalinkHost} from "../../../utils/permalinks/Permalinks";
import {toRightOf} from "../../structures/ContextMenu";
+import {copyPlaintext} from "../../../utils/strings";
export default createReactClass({
displayName: 'TextualBody',
@@ -69,23 +70,6 @@ export default createReactClass({
};
},
- copyToClipboard: function(text) {
- const textArea = document.createElement("textarea");
- textArea.value = text;
- document.body.appendChild(textArea);
- textArea.select();
-
- let successful = false;
- try {
- successful = document.execCommand('copy');
- } catch (err) {
- console.log('Unable to copy');
- }
-
- document.body.removeChild(textArea);
- return successful;
- },
-
// TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
UNSAFE_componentWillMount: function() {
this._content = createRef();
@@ -277,17 +261,17 @@ export default createReactClass({
Array.from(ReactDOM.findDOMNode(this).querySelectorAll('.mx_EventTile_body pre')).forEach((p) => {
const button = document.createElement("span");
button.className = "mx_EventTile_copyButton";
- button.onclick = (e) => {
+ button.onclick = async () => {
const copyCode = button.parentNode.getElementsByTagName("pre")[0];
- const successful = this.copyToClipboard(copyCode.textContent);
+ const successful = await copyPlaintext(copyCode.textContent);
- const buttonRect = e.target.getBoundingClientRect();
+ const buttonRect = button.getBoundingClientRect();
const GenericTextContextMenu = sdk.getComponent('context_menus.GenericTextContextMenu');
const {close} = ContextMenu.createMenu(GenericTextContextMenu, {
...toRightOf(buttonRect, 2),
message: successful ? _t('Copied!') : _t('Failed to copy'),
});
- e.target.onmouseleave = close;
+ button.onmouseleave = close;
};
// Wrap a div around
so that the copy button can be correctly positioned
diff --git a/src/components/views/room_settings/RoomPublishSetting.js b/src/components/views/room_settings/RoomPublishSetting.js
index bac2dfc656..6cc3ce26ba 100644
--- a/src/components/views/room_settings/RoomPublishSetting.js
+++ b/src/components/views/room_settings/RoomPublishSetting.js
@@ -18,7 +18,9 @@ import React from 'react';
import LabelledToggleSwitch from "../elements/LabelledToggleSwitch";
import {_t} from "../../../languageHandler";
import {MatrixClientPeg} from "../../../MatrixClientPeg";
+import {replaceableComponent} from "../../../utils/replaceableComponent";
+@replaceableComponent("views.room_settings.RoomPublishSetting")
export default class RoomPublishSetting extends React.PureComponent {
constructor(props) {
super(props);
diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js
index 0a8947f2c2..edf860c4c2 100644
--- a/src/components/views/verification/VerificationShowSas.js
+++ b/src/components/views/verification/VerificationShowSas.js
@@ -20,6 +20,7 @@ import { _t, _td } from '../../../languageHandler';
import {PendingActionSpinner} from "../right_panel/EncryptionInfo";
import AccessibleButton from "../elements/AccessibleButton";
import DialogButtons from "../elements/DialogButtons";
+import { fixupColorFonts } from '../../../utils/FontManager';
function capFirst(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
@@ -44,6 +45,13 @@ export default class VerificationShowSas extends React.Component {
};
}
+ componentWillMount() {
+ // As this component is also used before login (during complete security),
+ // also make sure we have a working emoji font to display the SAS emojis here.
+ // This is also done from LoggedInView.
+ fixupColorFonts();
+ }
+
onMatchClick = () => {
this.setState({ pending: true });
this.props.onDone();
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 84c172ea4d..a291065145 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -70,7 +70,7 @@
"Failure to create room": "Failure to create room",
"If you cancel now, you won't complete verifying the other user.": "If you cancel now, you won't complete verifying the other user.",
"If you cancel now, you won't complete verifying your other session.": "If you cancel now, you won't complete verifying your other session.",
- "If you cancel now, you won't complete your secret storage operation.": "If you cancel now, you won't complete your secret storage operation.",
+ "If you cancel now, you won't complete your operation.": "If you cancel now, you won't complete your operation.",
"Cancel entering passphrase?": "Cancel entering passphrase?",
"Enter passphrase": "Enter passphrase",
"Cancel": "Cancel",
@@ -444,7 +444,7 @@
"Send read receipts for messages (requires compatible homeserver to disable)": "Send read receipts for messages (requires compatible homeserver to disable)",
"Show previews/thumbnails for images": "Show previews/thumbnails for images",
"Enable message search in encrypted rooms": "Enable message search in encrypted rooms",
- "Keep secret storage passphrase in memory for this session": "Keep secret storage passphrase in memory for this session",
+ "Keep recovery passphrase in memory for this session": "Keep recovery passphrase in memory for this session",
"How fast should messages be downloaded.": "How fast should messages be downloaded.",
"Manually verify all remote sessions": "Manually verify all remote sessions",
"Collecting app version information": "Collecting app version information",
@@ -1772,18 +1772,19 @@
"Upload %(count)s other files|one": "Upload %(count)s other file",
"Cancel All": "Cancel All",
"Upload Error": "Upload Error",
+ "Verify other session": "Verify other session",
"Verification Request": "Verification Request",
"A widget would like to verify your identity": "A widget would like to verify your identity",
"A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.": "A widget located at %(widgetUrl)s would like to verify your identity. By allowing this, the widget will be able to verify your user ID, but not perform actions as you.",
"Remember my selection for this widget": "Remember my selection for this widget",
"Allow": "Allow",
"Deny": "Deny",
- "Enter secret storage passphrase": "Enter secret storage passphrase",
- "Unable to access secret storage. Please verify that you entered the correct passphrase.": "Unable to access secret storage. Please verify that you entered the correct passphrase.",
- "Warning : You should only access secret storage from a trusted computer.": "Warning : You should only access secret storage from a trusted computer.",
- "Access your secure message history and your cross-signing identity for verifying other sessions by entering your passphrase.": "Access your secure message history and your cross-signing identity for verifying other sessions by entering your passphrase.",
- "If you've forgotten your passphrase you can use your recovery key or set up new recovery options .": "If you've forgotten your passphrase you can use your recovery key or set up new recovery options .",
- "Enter secret storage recovery key": "Enter secret storage recovery key",
+ "Enter recovery passphrase": "Enter recovery passphrase",
+ "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.": "Unable to access secret storage. Please verify that you entered the correct recovery passphrase.",
+ "Warning : You should only do this on a trusted computer.": "Warning : You should only do this on a trusted computer.",
+ "Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.": "Access your secure message history and your cross-signing identity for verifying other sessions by entering your recovery passphrase.",
+ "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options .": "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options .",
+ "Enter recovery key": "Enter recovery key",
"Unable to access secret storage. Please verify that you entered the correct recovery key.": "Unable to access secret storage. Please verify that you entered the correct recovery key.",
"This looks like a valid recovery key!": "This looks like a valid recovery key!",
"Not a valid recovery key": "Not a valid recovery key",
@@ -1791,19 +1792,17 @@
"If you've forgotten your recovery key you can set up new recovery options .": "If you've forgotten your recovery key you can set up new recovery options .",
"Unable to load backup status": "Unable to load backup status",
"Recovery key mismatch": "Recovery key mismatch",
- "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.",
+ "Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this recovery key: please verify that you entered the correct recovery key.",
"Incorrect recovery passphrase": "Incorrect recovery passphrase",
- "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.",
+ "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this recovery passphrase: please verify that you entered the correct recovery passphrase.",
"Unable to restore backup": "Unable to restore backup",
"No backup found!": "No backup found!",
"Backup restored": "Backup restored",
"Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!",
"Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
- "Enter recovery passphrase": "Enter recovery passphrase",
"Warning : you should only set up key backup from a trusted computer.": "Warning : you should only set up key backup from a trusted computer.",
"Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Access your secure message history and set up secure messaging by entering your recovery passphrase.",
"If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options ": "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options ",
- "Enter recovery key": "Enter recovery key",
"Warning : You should only set up key backup from a trusted computer.": "Warning : You should only set up key backup from a trusted computer.",
"Access your secure message history and set up secure messaging by entering your recovery key.": "Access your secure message history and set up secure messaging by entering your recovery key.",
"If you've forgotten your recovery key you can set up new recovery options ": "If you've forgotten your recovery key you can set up new recovery options ",
@@ -2064,7 +2063,6 @@
"Uploading %(filename)s and %(count)s others|zero": "Uploading %(filename)s",
"Uploading %(filename)s and %(count)s others|one": "Uploading %(filename)s and %(count)s other",
"Could not load user profile": "Could not load user profile",
- "Complete security": "Complete security",
"Session verified": "Session verified",
"Failed to send email": "Failed to send email",
"The email address linked to your account must be entered.": "The email address linked to your account must be entered.",
@@ -2119,7 +2117,7 @@
"Registration Successful": "Registration Successful",
"Create your account": "Create your account",
"Use an existing session to verify this one, granting it access to encrypted messages.": "Use an existing session to verify this one, granting it access to encrypted messages.",
- "If you can’t access one, use your recovery key or passphrase. ": "If you can’t access one, use your recovery key or passphrase. ",
+ "If you can’t access one, use your recovery key or recovery passphrase. ": "If you can’t access one, use your recovery key or recovery passphrase. ",
"Use your other device to continue…": "Use your other device to continue…",
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.",
"Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.",
@@ -2182,18 +2180,17 @@
"Restore": "Restore",
"You'll need to authenticate with the server to confirm the upgrade.": "You'll need to authenticate with the server to confirm the upgrade.",
"Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.",
- "Great! This passphrase looks strong enough.": "Great! This passphrase looks strong enough.",
- "Set up encryption on this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.": "Set up encryption on this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.",
- "Secure your encryption keys with a passphrase. For maximum security this should be different to your account password:": "Secure your encryption keys with a passphrase. For maximum security this should be different to your account password:",
- "Enter a passphrase": "Enter a passphrase",
- "Back up my encryption keys, securing them with the same passphrase": "Back up my encryption keys, securing them with the same passphrase",
+ "Great! This recovery passphrase looks strong enough.": "Great! This recovery passphrase looks strong enough.",
+ "Set a recovery passphrase to secure encrypted information and recover it if you log out. This should be different to your account password:": "Set a recovery passphrase to secure encrypted information and recover it if you log out. This should be different to your account password:",
+ "Enter a recovery passphrase": "Enter a recovery passphrase",
+ "Back up encrypted message keys": "Back up encrypted message keys",
"Set up with a recovery key": "Set up with a recovery key",
"That matches!": "That matches!",
"That doesn't match.": "That doesn't match.",
"Go back to set it again.": "Go back to set it again.",
- "Enter your passphrase a second time to confirm it.": "Enter your passphrase a second time to confirm it.",
- "Confirm your passphrase": "Confirm your passphrase",
- "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.": "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your passphrase.",
+ "Enter your recovery passphrase a second time to confirm it.": "Enter your recovery passphrase a second time to confirm it.",
+ "Confirm your recovery passphrase": "Confirm your recovery passphrase",
+ "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.": "Your recovery key is a safety net - you can use it to restore access to your encrypted messages if you forget your recovery passphrase.",
"Keep a copy of it somewhere secure, like a password manager or even a safe.": "Keep a copy of it somewhere secure, like a password manager or even a safe.",
"Your recovery key": "Your recovery key",
"Copy": "Copy",
@@ -2205,19 +2202,20 @@
"Copy it to your personal cloud storage": "Copy it to your personal cloud storage",
"You can now verify your other devices, and other users to keep your chats safe.": "You can now verify your other devices, and other users to keep your chats safe.",
"Upgrade your encryption": "Upgrade your encryption",
+ "Confirm recovery passphrase": "Confirm recovery passphrase",
"Make a copy of your recovery key": "Make a copy of your recovery key",
"You're done!": "You're done!",
"Unable to set up secret storage": "Unable to set up secret storage",
"Retry": "Retry",
- "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.": "We'll store an encrypted copy of your keys on our server. Protect your backup with a passphrase to keep it secure.",
+ "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.": "We'll store an encrypted copy of your keys on our server. Secure your backup with a recovery passphrase.",
"For maximum security, this should be different from your account password.": "For maximum security, this should be different from your account password.",
- "Enter a passphrase...": "Enter a passphrase...",
- "Please enter your passphrase a second time to confirm.": "Please enter your passphrase a second time to confirm.",
- "Repeat your passphrase...": "Repeat your passphrase...",
+ "Enter a recovery passphrase...": "Enter a recovery passphrase...",
+ "Please enter your recovery passphrase a second time to confirm.": "Please enter your recovery passphrase a second time to confirm.",
+ "Repeat your recovery passphrase...": "Repeat your recovery passphrase...",
"Your keys are being backed up (the first backup could take a few minutes).": "Your keys are being backed up (the first backup could take a few minutes).",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.": "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another session.",
"Set up Secure Message Recovery": "Set up Secure Message Recovery",
- "Secure your backup with a passphrase": "Secure your backup with a passphrase",
+ "Secure your backup with a recovery passphrase": "Secure your backup with a recovery passphrase",
"Starting backup...": "Starting backup...",
"Success!": "Success!",
"Create key backup": "Create key backup",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index b539591efd..232c5d9f66 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -516,7 +516,7 @@ export const SETTINGS = {
},
"keepSecretStoragePassphraseForSession": {
supportedLevels: ['device', 'config'],
- displayName: _td("Keep secret storage passphrase in memory for this session"),
+ displayName: _td("Keep recovery passphrase in memory for this session"),
default: false,
},
"crawlerSleepTime": {
diff --git a/src/utils/strings.ts b/src/utils/strings.ts
new file mode 100644
index 0000000000..5856682445
--- /dev/null
+++ b/src/utils/strings.ts
@@ -0,0 +1,75 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/**
+ * Copy plaintext to user's clipboard
+ * It will overwrite user's selection range
+ * In certain browsers it may only work if triggered by a user action or may ask user for permissions
+ * Tries to use new async clipboard API if available
+ * @param text the plaintext to put in the user's clipboard
+ */
+export async function copyPlaintext(text: string): Promise {
+ try {
+ if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
+ await navigator.clipboard.writeText(text);
+ return true;
+ } else {
+ const textArea = document.createElement("textarea");
+ textArea.value = text;
+
+ // Avoid scrolling to bottom
+ textArea.style.top = "0";
+ textArea.style.left = "0";
+ textArea.style.position = "fixed";
+
+ document.body.appendChild(textArea);
+ const selection = document.getSelection();
+ const range = document.createRange();
+ // range.selectNodeContents(textArea);
+ range.selectNode(textArea);
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ const successful = document.execCommand("copy");
+ selection.removeAllRanges();
+ document.body.removeChild(textArea);
+ return successful;
+ }
+ } catch (e) {
+ console.error("copyPlaintext failed", e);
+ }
+ return false;
+}
+
+export function selectText(target: Element) {
+ const range = document.createRange();
+ range.selectNodeContents(target);
+
+ const selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+}
+
+/**
+ * Copy rich text to user's clipboard
+ * It will overwrite user's selection range
+ * In certain browsers it may only work if triggered by a user action or may ask user for permissions
+ * @param ref pointer to the node to copy
+ */
+export function copyNode(ref: Element): boolean {
+ selectText(ref);
+ return document.execCommand('copy');
+}
diff --git a/test/components/views/dialogs/AccessSecretStorageDialog-test.js b/test/components/views/dialogs/AccessSecretStorageDialog-test.js
index 30512ca4dd..c754a4b607 100644
--- a/test/components/views/dialogs/AccessSecretStorageDialog-test.js
+++ b/test/components/views/dialogs/AccessSecretStorageDialog-test.js
@@ -100,7 +100,7 @@ describe("AccessSecretStorageDialog", function() {
});
expect(notification.props.children).toEqual(
["\uD83D\uDC4E ", "Unable to access secret storage. Please verify that you " +
- "entered the correct passphrase."]);
+ "entered the correct recovery passphrase."]);
done();
});
});