/
copier.service.ts
99 lines (83 loc) 路 2.97 KB
/
copier.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* This class is based on the code in the following projects:
*
* - https://github.com/zenorocha/select
* - https://github.com/zenorocha/clipboard.js/
*
* Both released under MIT license - 漏 Zeno Rocha
*
* It is also influenced by the Angular CDK `PendingCopy` class:
* https://github.com/angular/components/blob/master/src/cdk/clipboard/pending-copy.ts
*/
export class CopierService {
/**
* Copy the contents of a `<textarea>` element to the clipboard.
*
* NOTE: For this method to work, the elements must be already inserted into the DOM.
*
* @param textArea The area containing the text to be copied to the clipboard.
* @return Whether the copy operation was successful.
*/
private copyTextArea(textArea: HTMLTextAreaElement): boolean {
const currentFocus = document.activeElement as HTMLOrSVGElement | null;
try {
textArea.select();
textArea.setSelectionRange(0, textArea.value.length);
return document.execCommand('copy');
} catch {
return false;
} finally {
// Calling `.select()` on the `<textarea>` element may have also focused it.
// Change the focus back to the previously focused element.
currentFocus?.focus();
}
}
/**
* Create a temporary, hidden `<textarea>` element and set its value to the specified text.
*
* @param text The text to be inserted into the textarea.
* @return The temporary `<textarea>` element containing the specified text.
*/
private createTextArea(text: string): HTMLTextAreaElement {
const docElem = document.documentElement;
const isRTL = docElem.getAttribute('dir') === 'rtl';
// Create a temporary element to hold the contents to copy.
const textArea = document.createElement('textarea');
const style = textArea.style;
// Prevent zooming on iOS.
style.fontSize = '12pt';
// Reset box model.
style.border = '0';
style.padding = '0';
style.margin = '0';
// Make the element invisible and move it out of screen horizontally.
style.opacity = '0';
style.position = 'fixed';
style.top = '0';
style[isRTL ? 'right' : 'left'] = '-999em';
textArea.setAttribute('aria-hidden', 'true');
textArea.setAttribute('readonly', '');
textArea.value = text;
return textArea;
}
/**
* Copy the specified text to the clipboard.
*
* @param text The text to be copied to the clipboard.
* @return Whether the copy operation was successful.
*/
copyText(text: string): boolean {
// Create a `<textarea>` element with the specified text.
const textArea = this.createTextArea(text);
// Insert it into the DOM.
document.body.appendChild(textArea);
// Copy its contents to the clipboard.
const success = this.copyTextArea(textArea);
// Remove it from the DOM, so it can be garbage-collected.
if (textArea.parentNode) {
// We cannot use ChildNode.remove() because of IE11.
textArea.parentNode.removeChild(textArea);
}
return success;
}
}