@sumit_yewale/angular 1.1.18 → 1.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,8 +6,7 @@
6
6
  /*
7
7
  * Public API Surface of angular-adapter
8
8
  */
9
- // export * from './lib/angular-adapter.service';
10
9
  export { CSVBoxButtonComponent } from './lib/csvbox-button.component';
11
10
  export { CSVBoxAngularModule } from './lib/csvbox-angular.module';
12
11
  export {} from './lib/interfaces/interface';
13
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BzdW1pdF95ZXdhbGUvYW5ndWxhci8iLCJzb3VyY2VzIjpbInB1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBS0Esc0NBQWMsK0JBQStCLENBQUM7QUFDOUMsb0NBQWMsNkJBQTZCLENBQUM7QUFDNUMsZUFBYyw0QkFBNEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgYW5ndWxhci1hZGFwdGVyXG4gKi9cblxuLy8gZXhwb3J0ICogZnJvbSAnLi9saWIvYW5ndWxhci1hZGFwdGVyLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvY3N2Ym94LWJ1dHRvbi5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvY3N2Ym94LWFuZ3VsYXIubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2ludGVyZmFjZXMvaW50ZXJmYWNlJztcbiJdfQ==
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BzdW1pdF95ZXdhbGUvYW5ndWxhci8iLCJzb3VyY2VzIjpbInB1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFJQSxzQ0FBYywrQkFBK0IsQ0FBQztBQUM5QyxvQ0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxlQUFjLDRCQUE0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBhbmd1bGFyLWFkYXB0ZXJcbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9jc3Zib3gtYnV0dG9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9jc3Zib3gtYW5ndWxhci5tb2R1bGUnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaW50ZXJmYWNlcy9pbnRlcmZhY2UnO1xuIl19
@@ -1,6 +1,6 @@
1
- import { SecurityContext, Component, ViewChild, Input, NgModule } from '@angular/core';
1
+ import { SecurityContext, Component, ChangeDetectorRef, NgZone, Input, NgModule } from '@angular/core';
2
2
  import { DomSanitizer } from '@angular/platform-browser';
3
- import { generateUuid, buildImportUrl, classifyStructuredMessage, buildInitPayload } from '@sumit_yewale/adapter-core';
3
+ import { createFileSender, classifyLegacyMessage, classifyStructuredMessage, generateUuid, buildImportUrl, buildInitPayload } from '@sumit_yewale/adapter-core';
4
4
 
5
5
  /**
6
6
  * @fileoverview added by tsickle
@@ -51,14 +51,133 @@ const insertCSS = (/**
51
51
  * Generated from: lib/csvbox-button.component.ts
52
52
  * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
53
53
  */
54
+ // How long we wait for the importer to confirm a file it was sent before giving up on it.
54
55
  /** @type {?} */
55
- const appVersion = '1.1.16';
56
+ const FILE_ACK_TIMEOUT_MS = 8000;
57
+ /**
58
+ * @record
59
+ */
60
+ function OpenImporterEntry() { }
61
+ if (false) {
62
+ /** @type {?} */
63
+ OpenImporterEntry.prototype.getHolder;
64
+ }
65
+ /**
66
+ * @record
67
+ */
68
+ function OpenImporters() { }
69
+ if (false) {
70
+ /** @type {?} */
71
+ OpenImporters.prototype.open;
72
+ /** @type {?} */
73
+ OpenImporters.prototype.listeners;
74
+ }
75
+ /** @type {?} */
76
+ const OPEN_IMPORTERS_KEY = '__csvboxOpenImporters';
77
+ /** @type {?} */
78
+ const TOP_Z_INDEX = 2147483647;
79
+ /**
80
+ * @return {?}
81
+ */
82
+ function openImporters() {
83
+ /** @type {?} */
84
+ const w = (/** @type {?} */ (window));
85
+ if (!w[OPEN_IMPORTERS_KEY])
86
+ w[OPEN_IMPORTERS_KEY] = { open: [], listeners: [] };
87
+ return w[OPEN_IMPORTERS_KEY];
88
+ }
89
+ /**
90
+ * @param {?} reg
91
+ * @return {?}
92
+ */
93
+ function restackOpenImporters(reg) {
94
+ reg.open.forEach((/**
95
+ * @param {?} entry
96
+ * @param {?} i
97
+ * @return {?}
98
+ */
99
+ (entry, i) => {
100
+ /** @type {?} */
101
+ const holder = entry.getHolder();
102
+ if (holder)
103
+ holder.style.zIndex = String(TOP_Z_INDEX - (reg.open.length - 1 - i));
104
+ }));
105
+ }
106
+ /**
107
+ * @param {?} entry
108
+ * @return {?}
109
+ */
110
+ function registerOpenImporter(entry) {
111
+ /** @type {?} */
112
+ const reg = openImporters();
113
+ if (reg.open.indexOf(entry) >= 0)
114
+ return;
115
+ reg.open.push(entry);
116
+ restackOpenImporters(reg);
117
+ reg.listeners.slice().forEach((/**
118
+ * @param {?} fn
119
+ * @return {?}
120
+ */
121
+ fn => fn()));
122
+ }
123
+ /**
124
+ * @param {?} entry
125
+ * @return {?}
126
+ */
127
+ function unregisterOpenImporter(entry) {
128
+ /** @type {?} */
129
+ const reg = openImporters();
130
+ /** @type {?} */
131
+ const i = reg.open.indexOf(entry);
132
+ if (i < 0)
133
+ return;
134
+ reg.open.splice(i, 1);
135
+ restackOpenImporters(reg);
136
+ reg.listeners.slice().forEach((/**
137
+ * @param {?} fn
138
+ * @return {?}
139
+ */
140
+ fn => fn()));
141
+ }
142
+ /**
143
+ * @param {?} entry
144
+ * @return {?}
145
+ */
146
+ function isBlockedByOpenImporter(entry) {
147
+ /** @type {?} */
148
+ const reg = openImporters();
149
+ return reg.open.length > 0 && reg.open.indexOf(entry) < 0;
150
+ }
151
+ /**
152
+ * @param {?} fn
153
+ * @return {?}
154
+ */
155
+ function subscribeOpenImporters(fn) {
156
+ /** @type {?} */
157
+ const reg = openImporters();
158
+ reg.listeners.push(fn);
159
+ return (/**
160
+ * @return {?}
161
+ */
162
+ () => {
163
+ /** @type {?} */
164
+ const i = reg.listeners.indexOf(fn);
165
+ if (i >= 0)
166
+ reg.listeners.splice(i, 1);
167
+ });
168
+ }
169
+ /** @type {?} */
170
+ const appVersion = '1.1.20';
56
171
  class CSVBoxButtonComponent {
57
172
  /**
58
173
  * @param {?} sanitizer
174
+ * @param {?} cdr
175
+ * @param {?} zone
59
176
  */
60
- constructor(sanitizer) {
177
+ constructor(sanitizer, cdr, zone) {
61
178
  this.sanitizer = sanitizer;
179
+ this.cdr = cdr;
180
+ this.zone = zone;
62
181
  this.isModalShown = false;
63
182
  this.licenseKey = null;
64
183
  this.uuid = null;
@@ -71,53 +190,121 @@ class CSVBoxButtonComponent {
71
190
  this.lazy = false;
72
191
  this.iframe = null;
73
192
  this.disabled = true;
74
- }
75
- /**
76
- * @return {?}
77
- */
78
- ngOnInit() {
79
- this.uuid = generateUuid();
80
- /** @type {?} */
81
- let iframeUrl = buildImportUrl({
82
- licenseKey: this.licenseKey,
83
- customDomain: this.customDomain,
84
- dataLocation: this.dataLocation,
85
- language: this.language,
86
- theme: this.theme,
87
- environment: this.environment
88
- }, "angular", appVersion);
89
- this.safeUrl = this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.sanitizer.bypassSecurityTrustResourceUrl(iframeUrl));
90
- }
91
- /**
92
- * @param {?} changes
93
- * @return {?}
94
- */
95
- ngOnChanges(changes) {
96
- if (changes["user"] && changes['user'].currentValue != changes['user'].previousValue) {
97
- this.updateUserVariabe(changes['user'].currentValue);
98
- }
99
- }
100
- /**
101
- * @param {?} data
102
- * @return {?}
103
- */
104
- updateUserVariabe(data) {
105
- this.user = data;
106
- if (this.iframe && this.iframe.contentWindow) {
107
- this.iframe.contentWindow.postMessage({
108
- "customer": data
109
- }, "*");
110
- }
111
- }
112
- /**
113
- * @return {?}
114
- */
115
- ngAfterContentInit() {
116
- window.addEventListener("message", (/**
193
+ // True while a different importer on the page is open: the button stays disabled.
194
+ this.blockedByOther = false;
195
+ this.registryEntry = { getHolder: (/**
196
+ * @return {?}
197
+ */
198
+ () => this.holder) };
199
+ this.fileSender = createFileSender({
200
+ getIframe: (/**
201
+ * @return {?}
202
+ */
203
+ () => this.iframe),
204
+ getToken: (/**
205
+ * @return {?}
206
+ */
207
+ () => (/** @type {?} */ (this.uuid))),
208
+ getTargetOrigin: (/**
209
+ * @return {?}
210
+ */
211
+ () => (/** @type {?} */ (this.targetOrigin))),
212
+ getBaseDomain: (/**
213
+ * @return {?}
214
+ */
215
+ () => this.baseDomain),
216
+ takeFile: (/**
217
+ * @return {?}
218
+ */
219
+ () => {
220
+ /** @type {?} */
221
+ const file = this.pendingFile;
222
+ this.pendingFile = null;
223
+ return file;
224
+ }),
225
+ onSent: (/**
226
+ * @return {?}
227
+ */
228
+ () => this.startFileAckTimer())
229
+ });
230
+ this.unsubscribeOpenImporters = null;
231
+ this.pendingFile = null;
232
+ // Data-location sheets redirect to another host, so the iframe origin can differ from
233
+ // targetOrigin. baseDomain is used to check the real origin before trusting it.
234
+ this.baseDomain = "app.csvbox.io";
235
+ this.fileAckTimer = null;
236
+ this.messageListener = (/**
117
237
  * @param {?} event
118
238
  * @return {?}
119
239
  */
120
240
  (event) => {
241
+ // Older importers send these as bare strings, without a token.
242
+ /** @type {?} */
243
+ const legacy = classifyLegacyMessage(event.data);
244
+ if (legacy) {
245
+ // Legacy messages carry no token, so the only way to tell which importer sent one is its
246
+ // window. Ignore those that came from another instance's iframe (or anywhere else).
247
+ if (!this.iframe || event.source !== this.iframe.contentWindow) {
248
+ return;
249
+ }
250
+ if (legacy.type === "mainModalHidden") {
251
+ this.handleModalClosed();
252
+ }
253
+ else if (legacy.type === "uploadSuccessful") {
254
+ if (this.onImport)
255
+ this.onImport(true);
256
+ if (this.isImported)
257
+ this.isImported(true);
258
+ if (this.imported)
259
+ this.imported(true);
260
+ }
261
+ else if (legacy.type === "uploadFailed") {
262
+ if (this.onImport)
263
+ this.onImport(false);
264
+ if (this.isImported)
265
+ this.isImported(false);
266
+ if (this.imported)
267
+ this.imported(false);
268
+ }
269
+ return;
270
+ }
271
+ // Set-file handshake messages. The shared core does not classify these, so they are
272
+ // read here, behind the same unique_token check the core applies.
273
+ /** @type {?} */
274
+ const raw = event.data;
275
+ if (raw && typeof raw === "object" && raw.data && raw.data.unique_token == this.uuid) {
276
+ this.fileSender.learnOrigin(event);
277
+ if (raw.type === "csvbox-set-file-rejected" && raw.data.reason === "not-a-file") {
278
+ // Reply to our probe (it has no file). It only tells us the origin, so do nothing.
279
+ return;
280
+ }
281
+ if (raw.type === "csvbox-modal-shown") {
282
+ this.clearFileAckTimer();
283
+ registerOpenImporter(this.registryEntry);
284
+ // What the file path in openModal() is waiting for. display as well as
285
+ // pointer-events: a second file declined while the first was still opening the
286
+ // modal has put the holder away in the meantime.
287
+ this.isModalShown = true;
288
+ if (this.holder) {
289
+ this.holder.style.display = 'block';
290
+ this.holder.style.pointerEvents = 'auto';
291
+ }
292
+ return;
293
+ }
294
+ if (raw.type === "csvbox-set-file-rejected") {
295
+ this.clearFileAckTimer();
296
+ // The importer has the file and will not take it. Put the holder away only if the
297
+ // modal was never confirmed up: a file declined while it is open leaves that modal
298
+ // where it is, and its own 'csvbox-modal-hidden' will put the holder away.
299
+ if (!this.isModalShown && this.holder) {
300
+ this.holder.style.display = 'none';
301
+ this.holder.style.pointerEvents = 'auto';
302
+ unregisterOpenImporter(this.registryEntry);
303
+ }
304
+ console.warn("[csvbox] importer declined the supplied file: " + raw.data.reason);
305
+ return;
306
+ }
307
+ }
121
308
  /** @type {?} */
122
309
  let message = classifyStructuredMessage(event.data, (/** @type {?} */ (this.uuid)));
123
310
  if (!message) {
@@ -161,7 +348,58 @@ class CSVBoxButtonComponent {
161
348
  if (this.imported)
162
349
  this.imported(false);
163
350
  }
164
- }), false);
351
+ });
352
+ }
353
+ /**
354
+ * @return {?}
355
+ */
356
+ ngOnInit() {
357
+ this.uuid = generateUuid();
358
+ /** @type {?} */
359
+ let iframeUrl = buildImportUrl({
360
+ licenseKey: this.licenseKey,
361
+ customDomain: this.customDomain,
362
+ dataLocation: this.dataLocation,
363
+ language: this.language,
364
+ theme: this.theme,
365
+ environment: this.environment
366
+ }, "angular", appVersion);
367
+ // Default place to send the file. A file is only ever sent to a named origin, never "*".
368
+ this.targetOrigin = new URL(iframeUrl).origin;
369
+ this.baseDomain = this.customDomain || "app.csvbox.io";
370
+ this.safeUrl = this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.sanitizer.bypassSecurityTrustResourceUrl(iframeUrl));
371
+ }
372
+ /**
373
+ * @param {?} changes
374
+ * @return {?}
375
+ */
376
+ ngOnChanges(changes) {
377
+ if (changes["user"] && changes['user'].currentValue != changes['user'].previousValue) {
378
+ this.updateUserVariabe(changes['user'].currentValue);
379
+ }
380
+ }
381
+ /**
382
+ * @param {?} data
383
+ * @return {?}
384
+ */
385
+ updateUserVariabe(data) {
386
+ this.user = data;
387
+ if (this.iframe && this.iframe.contentWindow) {
388
+ this.iframe.contentWindow.postMessage({
389
+ "customer": data
390
+ }, "*");
391
+ }
392
+ }
393
+ /**
394
+ * @return {?}
395
+ */
396
+ ngAfterContentInit() {
397
+ window.addEventListener("message", this.messageListener, false);
398
+ this.syncBlocked();
399
+ this.unsubscribeOpenImporters = subscribeOpenImporters((/**
400
+ * @return {?}
401
+ */
402
+ () => this.syncBlocked()));
165
403
  if (this.lazy) {
166
404
  this.disabled = false;
167
405
  }
@@ -174,8 +412,10 @@ class CSVBoxButtonComponent {
174
412
  * @return {?}
175
413
  */
176
414
  handleModalClosed() {
177
- if (this.holder)
415
+ if (this.holder) {
178
416
  this.holder.style.display = 'none';
417
+ this.holder.style.pointerEvents = 'auto';
418
+ }
179
419
  this.isModalShown = false;
180
420
  this.isIframeLoaded = false;
181
421
  this.openModalOnIframeLoad = false;
@@ -183,6 +423,9 @@ class CSVBoxButtonComponent {
183
423
  this.holder.remove();
184
424
  this.holder = null;
185
425
  this.iframe = null;
426
+ // A new iframe is built on the next open, so the origin is learned again.
427
+ this.clearProbeTimer();
428
+ unregisterOpenImporter(this.registryEntry);
186
429
  if (this.onClose)
187
430
  this.onClose();
188
431
  if (this.isClosed)
@@ -202,6 +445,7 @@ class CSVBoxButtonComponent {
202
445
  let iframe = document.createElement("iframe");
203
446
  this.iframe = iframe;
204
447
  iframe.setAttribute("src", this.safeUrl);
448
+ iframe.setAttribute("allow", "clipboard-read; clipboard-write *");
205
449
  iframe.frameBorder = "0";
206
450
  /** @type {?} */
207
451
  let self = this;
@@ -229,11 +473,16 @@ class CSVBoxButtonComponent {
229
473
  this.holder.setAttribute('id', `csvbox-embed-${this.uuid}`);
230
474
  this.holder.appendChild(iframe);
231
475
  document.body.insertAdjacentElement('beforeend', this.holder);
476
+ // The holder did not exist yet if openModal() asked for the importer before it was built.
477
+ restackOpenImporters(openImporters());
232
478
  }
233
479
  /**
234
480
  * @return {?}
235
481
  */
236
482
  openModal() {
483
+ // Counts as open from the moment it is requested, so the other buttons are disabled while
484
+ // this importer is still loading, and so it is stacked above any importer opened earlier.
485
+ registerOpenImporter(this.registryEntry);
237
486
  if (!this.iframe) {
238
487
  this.openModalOnIframeLoad = true;
239
488
  this.initImporter();
@@ -241,11 +490,36 @@ class CSVBoxButtonComponent {
241
490
  }
242
491
  if (!this.isModalShown) {
243
492
  if (this.isIframeLoaded) {
244
- this.isModalShown = true;
245
- if (this.holder)
246
- this.holder.style.display = 'block';
247
- if (this.iframe && this.iframe.contentWindow) {
248
- this.iframe.contentWindow.postMessage('openModal', '*');
493
+ if (this.pendingFile) {
494
+ // The importer opens its own modal once it has the file, so that it can inject on
495
+ // 'shown.bs.modal'. Sending 'openModal' as well would race that.
496
+ //
497
+ // It can also decline: wrong step, an import file URL configured on the sheet, or
498
+ // an importer too old to know the message at all. So the holder goes up
499
+ // click-through and stays that way until 'csvbox-modal-shown' confirms the modal
500
+ // is really up. It covers the viewport at z-index 2147483647 and the importer
501
+ // renders transparent with its modal closed, so arming it on an unanswered message
502
+ // leaves an invisible sheet over the host page eating every click.
503
+ //
504
+ // display:block regardless, so the iframe lays out and animates normally; only
505
+ // pointer-events is held back. isModalShown likewise waits for the confirmation,
506
+ // or a declined file would latch the importer shut for good.
507
+ if (this.holder) {
508
+ this.holder.style.pointerEvents = 'none';
509
+ this.holder.style.display = 'block';
510
+ }
511
+ this.fileSender.send();
512
+ }
513
+ else {
514
+ this.isModalShown = true;
515
+ if (this.holder) {
516
+ // Explicit: a previously declined file leaves the holder click-through.
517
+ this.holder.style.pointerEvents = 'auto';
518
+ this.holder.style.display = 'block';
519
+ }
520
+ if (this.iframe && this.iframe.contentWindow) {
521
+ this.iframe.contentWindow.postMessage('openModal', '*');
522
+ }
249
523
  }
250
524
  }
251
525
  else {
@@ -253,13 +527,118 @@ class CSVBoxButtonComponent {
253
527
  }
254
528
  }
255
529
  }
530
+ /**
531
+ * Open the importer on a File the host page already has, instead of the file picker.
532
+ *
533
+ * Reachable through a template reference (`#importer` then `importer.openModalWithFile(file)`)
534
+ * or `\@ViewChild(CSVBoxButtonComponent)`.
535
+ *
536
+ * The File crosses to the iframe by structured clone, so the importer receives the real
537
+ * object and applies its own extension, worksheet and size rules to it -- this does not
538
+ * bypass any of them. Pass a File; a Blob has no name for the importer to read an
539
+ * extension from.
540
+ * @param {?} file
541
+ * @return {?}
542
+ */
543
+ openModalWithFile(file) {
544
+ if (typeof File === 'undefined' || !(file instanceof File)) {
545
+ return;
546
+ }
547
+ this.pendingFile = file;
548
+ // Already open: hand it over now rather than holding it for the next open. The importer
549
+ // takes it only while it is still on the upload step, and ignores it once the user has a
550
+ // dataset and a mapping in progress.
551
+ if (this.isModalShown && this.iframe && this.isIframeLoaded) {
552
+ this.fileSender.send();
553
+ return;
554
+ }
555
+ this.openModal();
556
+ }
557
+ /**
558
+ * @return {?}
559
+ */
560
+ clearProbeTimer() {
561
+ this.clearFileAckTimer();
562
+ this.fileSender.reset();
563
+ }
564
+ /**
565
+ * @return {?}
566
+ */
567
+ startFileAckTimer() {
568
+ this.clearFileAckTimer();
569
+ this.fileAckTimer = setTimeout((/**
570
+ * @return {?}
571
+ */
572
+ () => {
573
+ this.fileAckTimer = null;
574
+ this.giveUpOnFile();
575
+ }), FILE_ACK_TIMEOUT_MS);
576
+ }
577
+ /**
578
+ * @return {?}
579
+ */
580
+ clearFileAckTimer() {
581
+ if (this.fileAckTimer) {
582
+ clearTimeout(this.fileAckTimer);
583
+ this.fileAckTimer = null;
584
+ }
585
+ }
586
+ // The importer never confirmed the file it was sent (an origin we do not trust, or an importer too
587
+ // old to know the message). Without this the holder would stay up, invisible and click-through,
588
+ // and the other instances' buttons would stay disabled for good.
589
+ /**
590
+ * @return {?}
591
+ */
592
+ giveUpOnFile() {
593
+ if (this.isModalShown) {
594
+ return;
595
+ }
596
+ /** @type {?} */
597
+ const holder = this.holder;
598
+ if (holder) {
599
+ holder.style.display = 'none';
600
+ holder.style.pointerEvents = 'auto';
601
+ }
602
+ unregisterOpenImporter(this.registryEntry);
603
+ console.warn("[csvbox] the importer did not respond to the supplied file");
604
+ }
605
+ /**
606
+ * @private
607
+ * @return {?}
608
+ */
609
+ syncBlocked() {
610
+ /** @type {?} */
611
+ const blocked = isBlockedByOpenImporter(this.registryEntry);
612
+ if (blocked !== this.blockedByOther) {
613
+ // The registry can call back from outside Angular's zone (another instance, another app).
614
+ this.zone.run((/**
615
+ * @return {?}
616
+ */
617
+ () => {
618
+ this.blockedByOther = blocked;
619
+ this.cdr.markForCheck();
620
+ }));
621
+ }
622
+ }
623
+ /**
624
+ * @return {?}
625
+ */
626
+ ngOnDestroy() {
627
+ this.clearProbeTimer();
628
+ window.removeEventListener("message", this.messageListener);
629
+ unregisterOpenImporter(this.registryEntry);
630
+ if (this.unsubscribeOpenImporters) {
631
+ this.unsubscribeOpenImporters();
632
+ this.unsubscribeOpenImporters = null;
633
+ }
634
+ }
256
635
  }
257
636
  CSVBoxButtonComponent.decorators = [
258
637
  { type: Component, args: [{
259
638
  selector: 'csvbox-button',
260
639
  template: `
261
640
  <div>
262
- <button [disabled]="disabled" #initiator (click)="openModal()" [attr.data-csvbox-token]="uuid">
641
+ <button [disabled]="disabled || blockedByOther" (click)="openModal()" [attr.data-csvbox-token]="uuid">
263
642
  <ng-content></ng-content>
264
643
  </button>
265
644
  </div>
@@ -268,10 +647,11 @@ CSVBoxButtonComponent.decorators = [
268
647
  ];
269
648
  /** @nocollapse */
270
649
  CSVBoxButtonComponent.ctorParameters = () => [
271
- { type: DomSanitizer }
650
+ { type: DomSanitizer },
651
+ { type: ChangeDetectorRef },
652
+ { type: NgZone }
272
653
  ];
273
654
  CSVBoxButtonComponent.propDecorators = {
274
- initiator: [{ type: ViewChild, args: ['initiator', { static: false },] }],
275
655
  onImport: [{ type: Input }],
276
656
  onReady: [{ type: Input }],
277
657
  onClose: [{ type: Input }],
@@ -304,8 +684,6 @@ if (false) {
304
684
  /** @type {?} */
305
685
  CSVBoxButtonComponent.prototype.isModalShown;
306
686
  /** @type {?} */
307
- CSVBoxButtonComponent.prototype.initiator;
308
- /** @type {?} */
309
687
  CSVBoxButtonComponent.prototype.onImport;
310
688
  /** @type {?} */
311
689
  CSVBoxButtonComponent.prototype.onReady;
@@ -364,9 +742,52 @@ if (false) {
364
742
  /** @type {?} */
365
743
  CSVBoxButtonComponent.prototype.disabled;
366
744
  /** @type {?} */
745
+ CSVBoxButtonComponent.prototype.blockedByOther;
746
+ /**
747
+ * @type {?}
748
+ * @private
749
+ */
750
+ CSVBoxButtonComponent.prototype.registryEntry;
751
+ /**
752
+ * @type {?}
753
+ * @private
754
+ */
755
+ CSVBoxButtonComponent.prototype.fileSender;
756
+ /**
757
+ * @type {?}
758
+ * @private
759
+ */
760
+ CSVBoxButtonComponent.prototype.unsubscribeOpenImporters;
761
+ /** @type {?} */
367
762
  CSVBoxButtonComponent.prototype.holder;
368
763
  /** @type {?} */
764
+ CSVBoxButtonComponent.prototype.pendingFile;
765
+ /** @type {?} */
766
+ CSVBoxButtonComponent.prototype.targetOrigin;
767
+ /** @type {?} */
768
+ CSVBoxButtonComponent.prototype.baseDomain;
769
+ /**
770
+ * @type {?}
771
+ * @private
772
+ */
773
+ CSVBoxButtonComponent.prototype.fileAckTimer;
774
+ /**
775
+ * @type {?}
776
+ * @private
777
+ */
778
+ CSVBoxButtonComponent.prototype.messageListener;
779
+ /** @type {?} */
369
780
  CSVBoxButtonComponent.prototype.sanitizer;
781
+ /**
782
+ * @type {?}
783
+ * @private
784
+ */
785
+ CSVBoxButtonComponent.prototype.cdr;
786
+ /**
787
+ * @type {?}
788
+ * @private
789
+ */
790
+ CSVBoxButtonComponent.prototype.zone;
370
791
  }
371
792
 
372
793
  /**