1 | import { DOCUMENT, CommonModule } from '@angular/common';
|
2 | import { ɵɵdefineInjectable, ɵɵinject, NgZone, Injectable, Inject, Optional, EventEmitter, Directive, ElementRef, Renderer2, Input, Output, ViewContainerRef, TemplateRef, NgModule } from '@angular/core';
|
3 | import { WINDOW } from 'ngx-window-token';
|
4 | import { Subject } from 'rxjs';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | class ClipboardService {
|
10 | constructor(ngZone, document, window) {
|
11 | this.ngZone = ngZone;
|
12 | this.document = document;
|
13 | this.window = window;
|
14 | this.copySubject = new Subject();
|
15 | this.copyResponse$ = this.copySubject.asObservable();
|
16 | this.config = {};
|
17 | }
|
18 | configure(config) {
|
19 | this.config = config;
|
20 | }
|
21 | copy(content) {
|
22 | if (!this.isSupported || !content) {
|
23 | return this.pushCopyResponse({ isSuccess: false, content });
|
24 | }
|
25 | const copyResult = this.copyFromContent(content);
|
26 | if (copyResult) {
|
27 | return this.pushCopyResponse({ content, isSuccess: copyResult });
|
28 | }
|
29 | return this.pushCopyResponse({ isSuccess: false, content });
|
30 | }
|
31 | get isSupported() {
|
32 | return !!this.document.queryCommandSupported && !!this.document.queryCommandSupported('copy') && !!this.window;
|
33 | }
|
34 | isTargetValid(element) {
|
35 | if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
36 | if (element.hasAttribute('disabled')) {
|
37 | throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
|
38 | }
|
39 | return true;
|
40 | }
|
41 | throw new Error('Target should be input or textarea');
|
42 | }
|
43 | |
44 |
|
45 |
|
46 | copyFromInputElement(targetElm, isFocus = true) {
|
47 | try {
|
48 | this.selectTarget(targetElm);
|
49 | const re = this.copyText();
|
50 | this.clearSelection(isFocus ? targetElm : undefined, this.window);
|
51 | return re && this.isCopySuccessInIE11();
|
52 | }
|
53 | catch (error) {
|
54 | return false;
|
55 | }
|
56 | }
|
57 | |
58 |
|
59 |
|
60 | isCopySuccessInIE11() {
|
61 | const clipboardData = this.window['clipboardData'];
|
62 | if (clipboardData && clipboardData.getData) {
|
63 | if (!clipboardData.getData('Text')) {
|
64 | return false;
|
65 | }
|
66 | }
|
67 | return true;
|
68 | }
|
69 | |
70 |
|
71 |
|
72 |
|
73 | copyFromContent(content, container = this.document.body) {
|
74 |
|
75 |
|
76 | if (this.tempTextArea && !container.contains(this.tempTextArea)) {
|
77 | this.destroy(this.tempTextArea.parentElement || undefined);
|
78 | }
|
79 | if (!this.tempTextArea) {
|
80 | this.tempTextArea = this.createTempTextArea(this.document, this.window);
|
81 | try {
|
82 | container.appendChild(this.tempTextArea);
|
83 | }
|
84 | catch (error) {
|
85 | throw new Error('Container should be a Dom element');
|
86 | }
|
87 | }
|
88 | this.tempTextArea.value = content;
|
89 | const toReturn = this.copyFromInputElement(this.tempTextArea, false);
|
90 | if (this.config.cleanUpAfterCopy) {
|
91 | this.destroy(this.tempTextArea.parentElement || undefined);
|
92 | }
|
93 | return toReturn;
|
94 | }
|
95 | |
96 |
|
97 |
|
98 | destroy(container = this.document.body) {
|
99 | if (this.tempTextArea) {
|
100 | container.removeChild(this.tempTextArea);
|
101 |
|
102 | this.tempTextArea = undefined;
|
103 | }
|
104 | }
|
105 | |
106 |
|
107 |
|
108 | selectTarget(inputElement) {
|
109 | inputElement.select();
|
110 | inputElement.setSelectionRange(0, inputElement.value.length);
|
111 | return inputElement.value.length;
|
112 | }
|
113 | copyText() {
|
114 | return this.document.execCommand('copy');
|
115 | }
|
116 | |
117 |
|
118 |
|
119 | clearSelection(inputElement, window) {
|
120 | var _a;
|
121 | inputElement && inputElement.focus();
|
122 | (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
|
123 | }
|
124 | |
125 |
|
126 |
|
127 | createTempTextArea(doc, window) {
|
128 | const isRTL = doc.documentElement.getAttribute('dir') === 'rtl';
|
129 | let ta;
|
130 | ta = doc.createElement('textarea');
|
131 |
|
132 | ta.style.fontSize = '12pt';
|
133 |
|
134 | ta.style.border = '0';
|
135 | ta.style.padding = '0';
|
136 | ta.style.margin = '0';
|
137 |
|
138 | ta.style.position = 'absolute';
|
139 | ta.style[isRTL ? 'right' : 'left'] = '-9999px';
|
140 |
|
141 | const yPosition = window.pageYOffset || doc.documentElement.scrollTop;
|
142 | ta.style.top = yPosition + 'px';
|
143 | ta.setAttribute('readonly', '');
|
144 | return ta;
|
145 | }
|
146 | |
147 |
|
148 |
|
149 |
|
150 | pushCopyResponse(response) {
|
151 | if (this.copySubject.observers.length > 0) {
|
152 | this.ngZone.run(() => {
|
153 | this.copySubject.next(response);
|
154 | });
|
155 | }
|
156 | }
|
157 | |
158 |
|
159 |
|
160 | pushCopyReponse(response) {
|
161 | this.pushCopyResponse(response);
|
162 | }
|
163 | }
|
164 | ClipboardService.ɵprov = ɵɵdefineInjectable({ factory: function ClipboardService_Factory() { return new ClipboardService(ɵɵinject(NgZone), ɵɵinject(DOCUMENT), ɵɵinject(WINDOW, 8)); }, token: ClipboardService, providedIn: "root" });
|
165 | ClipboardService.decorators = [
|
166 | { type: Injectable, args: [{ providedIn: 'root' },] }
|
167 | ];
|
168 | ClipboardService.ctorParameters = () => [
|
169 | { type: NgZone },
|
170 | { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
|
171 | { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [WINDOW,] }] }
|
172 | ];
|
173 |
|
174 | class ClipboardDirective {
|
175 | constructor(ngZone, host, renderer, clipboardSrv) {
|
176 | this.ngZone = ngZone;
|
177 | this.host = host;
|
178 | this.renderer = renderer;
|
179 | this.clipboardSrv = clipboardSrv;
|
180 | this.cbOnSuccess = new EventEmitter();
|
181 | this.cbOnError = new EventEmitter();
|
182 | this.onClick = (event) => {
|
183 | if (!this.clipboardSrv.isSupported) {
|
184 | this.handleResult(false, undefined, event);
|
185 | }
|
186 | else if (this.targetElm && this.clipboardSrv.isTargetValid(this.targetElm)) {
|
187 | this.handleResult(this.clipboardSrv.copyFromInputElement(this.targetElm), this.targetElm.value, event);
|
188 | }
|
189 | else if (this.cbContent) {
|
190 | this.handleResult(this.clipboardSrv.copyFromContent(this.cbContent, this.container), this.cbContent, event);
|
191 | }
|
192 | };
|
193 | }
|
194 |
|
195 | ngOnInit() {
|
196 | this.ngZone.runOutsideAngular(() => {
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | this.clickListener = this.renderer.listen(this.host.nativeElement, 'click', this.onClick);
|
202 | });
|
203 | }
|
204 | ngOnDestroy() {
|
205 | this.clickListener();
|
206 | this.clipboardSrv.destroy(this.container);
|
207 | }
|
208 | |
209 |
|
210 |
|
211 |
|
212 | handleResult(succeeded, copiedContent, event) {
|
213 | let response = {
|
214 | isSuccess: succeeded,
|
215 | event
|
216 | };
|
217 | if (succeeded) {
|
218 | if (this.cbOnSuccess.observers.length > 0) {
|
219 | response = Object.assign(response, {
|
220 | content: copiedContent,
|
221 | successMessage: this.cbSuccessMsg
|
222 | });
|
223 | this.ngZone.run(() => {
|
224 | this.cbOnSuccess.emit(response);
|
225 | });
|
226 | }
|
227 | }
|
228 | else {
|
229 | if (this.cbOnError.observers.length > 0) {
|
230 | this.ngZone.run(() => {
|
231 | this.cbOnError.emit(response);
|
232 | });
|
233 | }
|
234 | }
|
235 | this.clipboardSrv.pushCopyResponse(response);
|
236 | }
|
237 | }
|
238 | ClipboardDirective.decorators = [
|
239 | { type: Directive, args: [{ selector: '[ngxClipboard]' },] }
|
240 | ];
|
241 | ClipboardDirective.ctorParameters = () => [
|
242 | { type: NgZone },
|
243 | { type: ElementRef },
|
244 | { type: Renderer2 },
|
245 | { type: ClipboardService }
|
246 | ];
|
247 | ClipboardDirective.propDecorators = {
|
248 | targetElm: [{ type: Input, args: ['ngxClipboard',] }],
|
249 | container: [{ type: Input }],
|
250 | cbContent: [{ type: Input }],
|
251 | cbSuccessMsg: [{ type: Input }],
|
252 | cbOnSuccess: [{ type: Output }],
|
253 | cbOnError: [{ type: Output }]
|
254 | };
|
255 |
|
256 | class ClipboardIfSupportedDirective {
|
257 | constructor(_clipboardService, _viewContainerRef, _templateRef) {
|
258 | this._clipboardService = _clipboardService;
|
259 | this._viewContainerRef = _viewContainerRef;
|
260 | this._templateRef = _templateRef;
|
261 | }
|
262 | ngOnInit() {
|
263 | if (this._clipboardService.isSupported) {
|
264 | this._viewContainerRef.createEmbeddedView(this._templateRef);
|
265 | }
|
266 | }
|
267 | }
|
268 | ClipboardIfSupportedDirective.decorators = [
|
269 | { type: Directive, args: [{
|
270 | selector: '[ngxClipboardIfSupported]'
|
271 | },] }
|
272 | ];
|
273 | ClipboardIfSupportedDirective.ctorParameters = () => [
|
274 | { type: ClipboardService },
|
275 | { type: ViewContainerRef },
|
276 | { type: TemplateRef }
|
277 | ];
|
278 |
|
279 | class ClipboardModule {
|
280 | }
|
281 | ClipboardModule.decorators = [
|
282 | { type: NgModule, args: [{
|
283 | imports: [CommonModule],
|
284 | declarations: [ClipboardDirective, ClipboardIfSupportedDirective],
|
285 | exports: [ClipboardDirective, ClipboardIfSupportedDirective]
|
286 | },] }
|
287 | ];
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 | export { ClipboardDirective, ClipboardIfSupportedDirective, ClipboardModule, ClipboardService };
|
298 |
|