Files
threshold-ui/ui/desktop/app/components/copyable/index.js
T

88 lines
2.5 KiB
JavaScript
Raw Normal View History

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/
2021-02-02 17:12:47 -05:00
import Component from '@glimmer/component';
import ClipboardJS from 'clipboard';
2021-02-02 17:12:47 -05:00
import { action } from '@ember/object';
2021-02-08 12:50:42 -05:00
import { getOwner } from '@ember/application';
2021-02-02 17:12:47 -05:00
import { generateComponentID } from 'rose/utilities/component-auto-id';
import { tracked } from '@glimmer/tracking';
import { later } from '@ember/runloop';
2021-02-02 17:12:47 -05:00
export default class CopyableComponent extends Component {
// =attributes
id = generateComponentID();
copyableButtonId = `copyable-button-${this.id}`;
2021-09-16 14:03:26 -07:00
actionIcon = 'flight-icons/svg/clipboard-copy-16';
successIcon = 'flight-icons/svg/clipboard-checked-16';
2021-02-02 17:12:47 -05:00
actionText = this.args.buttonText;
successText = this.args.acknowledgeText;
@tracked copied = false;
clipboard = null;
confirmCopy() {
2021-02-02 17:12:47 -05:00
this.copied = true;
later(() => (this.copied = false), 1000);
}
2021-02-02 17:12:47 -05:00
/**
* Checks for ClipboardJS support.
* @return {boolean}
*/
get isClipboardLibrarySupported() {
return ClipboardJS.isSupported();
}
2021-02-08 12:50:42 -05:00
// =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];
}
2021-02-02 17:12:47 -05:00
// =actions
/**
* Initialize ClipboardJS library and register for it's events.
*/
@action
register() {
2021-03-05 17:27:00 -05:00
this.tearDown();
2021-02-02 17:12:47 -05:00
/* istanbul ignore next */
this.clipboard = new ClipboardJS(`#${this.copyableButtonId}`, {
text: () => this.args.text,
2021-02-08 12:50:42 -05:00
// 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'),
2021-02-02 17:12:47 -05:00
});
/* istanbul ignore next */
this.clipboard.on('success', (clipboardEvent) => {
clipboardEvent.clearSelection();
this.confirmCopy();
2021-02-02 17:12:47 -05:00
});
}
/**
* Destroy ClipboardJS library instance and cancel icon timer.
*/
@action
2021-03-05 17:27:00 -05:00
tearDown() {
2021-02-02 17:12:47 -05:00
this.clipboard?.destroy();
this.clipboard = null;
}
}