From d68cc83adf44b0d0126dda6a52b358db1eb8432b Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Mon, 8 Feb 2021 12:50:42 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20allow=20copyable=20to=20w?= =?UTF-8?q?ork=20within=20a=20modal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/desktop/app/components/copyable/index.js | 22 ++++++++++++++++++++- ui/desktop/app/templates/application.hbs | 18 ++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/ui/desktop/app/components/copyable/index.js b/ui/desktop/app/components/copyable/index.js index 17652e911..3de4687ff 100644 --- a/ui/desktop/app/components/copyable/index.js +++ b/ui/desktop/app/components/copyable/index.js @@ -1,9 +1,10 @@ import Component from '@glimmer/component'; -import ClipboardJS from 'clipboard'; import { action } from '@ember/object'; +import { getOwner } from '@ember/application'; import { generateComponentID } from 'rose/utilities/component-auto-id'; import { task, timeout } from 'ember-concurrency'; import { tracked } from '@glimmer/tracking'; +import ClipboardJS from 'clipboard'; export default class CopyableComponent extends Component { @@ -46,6 +47,18 @@ export default class CopyableComponent extends Component { return ClipboardJS.isSupported(); } + // =methods + + /** + * Returns the first element with the specified class name if exists, + * otherwise undefined. + * @return {?HTMLElement} + */ + getFirstElementByClassName(className) { + const document = getOwner(this).lookup('service:-document').documentElement; + return document.getElementsByClassName(className)[0]; + } + // =actions /** @@ -57,6 +70,13 @@ export default class CopyableComponent extends Component { /* istanbul ignore next */ this.clipboard = new ClipboardJS(`#${this.copyableButtonId}`, { text: () => this.args.text, + // ClipboardJS depends on inserting a hidden textarea that receives + // focus in order to copy text to the clipboard. However, our modal + // has a focus trap that prevents this focus. Thus we try to set the + // container to a modal (if exists), since this is the only container + // a user would be able to interact with. If a modal doesn't exist, + // container is set to `undefined` and thus uses the default body element. + container: this.getFirstElementByClassName('rose-dialog') }); /* istanbul ignore next */ this.clipboard.on('success', (clipboardEvent) => { diff --git a/ui/desktop/app/templates/application.hbs b/ui/desktop/app/templates/application.hbs index 6dfa45877..9c504be7b 100644 --- a/ui/desktop/app/templates/application.hbs +++ b/ui/desktop/app/templates/application.hbs @@ -57,11 +57,19 @@ @dismiss={{accept}} as |dialog|> - {{t 'states.connection.success.description' - port=confirmation.text.port - address=confirmation.text.address - protocol=confirmation.text.protocol - }} + + + {{t 'states.connection.success.description' + port=confirmation.text.port + address=confirmation.text.address + protocol=confirmation.text.protocol + }} + +