ngx-doc-viewer 2.0.4 → 2.1.0

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.
Files changed (44) hide show
  1. package/README.md +1 -1
  2. package/esm2020/index.mjs +4 -0
  3. package/esm2020/lib/document-viewer.component.mjs +188 -0
  4. package/esm2020/lib/document-viewer.module.mjs +18 -0
  5. package/esm2020/ngx-doc-viewer.mjs +5 -0
  6. package/fesm2015/ngx-doc-viewer.mjs +211 -0
  7. package/fesm2015/ngx-doc-viewer.mjs.map +1 -0
  8. package/fesm2020/ngx-doc-viewer.mjs +208 -0
  9. package/fesm2020/ngx-doc-viewer.mjs.map +1 -0
  10. package/{ngx-doc-viewer/src/index.d.ts → index.d.ts} +1 -2
  11. package/{ngx-doc-viewer/src/lib → lib}/document-viewer.component.d.ts +7 -4
  12. package/lib/document-viewer.module.d.ts +8 -0
  13. package/ngx-doc-viewer.d.ts +2 -1
  14. package/package.json +25 -12
  15. package/bundles/ngx-doc-viewer.umd.js +0 -729
  16. package/bundles/ngx-doc-viewer.umd.js.map +0 -1
  17. package/esm2015/helper.js +0 -202
  18. package/esm2015/helper.js.map +0 -1
  19. package/esm2015/helper.metadata.json +0 -1
  20. package/esm2015/model.js +0 -14
  21. package/esm2015/model.js.map +0 -1
  22. package/esm2015/model.metadata.json +0 -1
  23. package/esm2015/ngx-doc-viewer/src/index.js +0 -5
  24. package/esm2015/ngx-doc-viewer/src/index.js.map +0 -1
  25. package/esm2015/ngx-doc-viewer/src/index.metadata.json +0 -1
  26. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.component.js +0 -178
  27. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.component.js.map +0 -1
  28. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.component.metadata.json +0 -1
  29. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.module.js +0 -13
  30. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.module.js.map +0 -1
  31. package/esm2015/ngx-doc-viewer/src/lib/document-viewer.module.metadata.json +0 -1
  32. package/esm2015/ngx-doc-viewer-wrapper.js +0 -2
  33. package/esm2015/ngx-doc-viewer-wrapper.js.map +0 -1
  34. package/esm2015/ngx-doc-viewer-wrapper.metadata.json +0 -1
  35. package/esm2015/ngx-doc-viewer.js +0 -5
  36. package/esm2015/ngx-doc-viewer.js.map +0 -1
  37. package/esm2015/ngx-doc-viewer.metadata.json +0 -1
  38. package/fesm2015/ngx-doc-viewer.js +0 -406
  39. package/fesm2015/ngx-doc-viewer.js.map +0 -1
  40. package/helper.d.ts +0 -24
  41. package/model.d.ts +0 -17
  42. package/ngx-doc-viewer/src/lib/document-viewer.module.d.ts +0 -2
  43. package/ngx-doc-viewer-wrapper.d.ts +0 -1
  44. package/ngx-doc-viewer.metadata.json +0 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ Pdf files and word document that are not publicly available can be shown using t
8
8
 
9
9
  <a href="https://angular-doc-viewer.firebaseapp.com/">View demo</a>
10
10
 
11
- <a href="https://github.com/Marcelh1983/document-viewer/blob/main/libs/ngx-doc-viewer/changelog.md">Changes</a>
11
+ <a href="https://github.com/Marcelh1983/document-viewer/blob/main/packages/ngx-doc-viewer/changelog.md">Changes</a>
12
12
 
13
13
  ### Install the NPM Module
14
14
 
@@ -0,0 +1,4 @@
1
+ export * from './lib/document-viewer.module';
2
+ export * from './lib/document-viewer.component';
3
+ export * from 'docviewhelper';
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wYWNrYWdlcy9uZ3gtZG9jLXZpZXdlci9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyw4QkFBOEIsQ0FBQztBQUM3QyxjQUFjLGlDQUFpQyxDQUFDO0FBQ2hELGNBQWMsZUFBZSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9saWIvZG9jdW1lbnQtdmlld2VyLm1vZHVsZSc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL2RvY3VtZW50LXZpZXdlci5jb21wb25lbnQnO1xyXG5leHBvcnQgKiBmcm9tICdkb2N2aWV3aGVscGVyJzsiXX0=
@@ -0,0 +1,188 @@
1
+ import { Component, Input, NgZone, Output, ViewChildren, QueryList, } from '@angular/core';
2
+ import { DomSanitizer } from '@angular/platform-browser';
3
+ import { EventEmitter } from '@angular/core';
4
+ // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
5
+ import { getDocxToHtml, getViewerDetails, googleCheckSubscription, iframeIsLoaded, isLocalFile, replaceLocalUrl } from 'docviewhelper';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "@angular/platform-browser";
8
+ import * as i2 from "@angular/common";
9
+ export class NgxDocViewerComponent {
10
+ constructor(domSanitizer, ngZone) {
11
+ this.domSanitizer = domSanitizer;
12
+ this.ngZone = ngZone;
13
+ this.loaded = new EventEmitter();
14
+ this.url = '';
15
+ this.queryParams = '';
16
+ this.viewerUrl = '';
17
+ this.googleCheckInterval = 3000;
18
+ this.googleMaxChecks = 5;
19
+ this.disableContent = 'none';
20
+ this.googleCheckContentLoaded = true;
21
+ this.viewer = 'google';
22
+ this.overrideLocalhost = '';
23
+ this.iframes = undefined;
24
+ this.fullUrl = undefined;
25
+ this.externalViewer = false;
26
+ this.docHtml = '';
27
+ this.configuredViewer = 'google';
28
+ this.checkIFrameSubscription = undefined;
29
+ this.shouldCheckIframe = false;
30
+ }
31
+ ngAfterViewInit() {
32
+ if (this.shouldCheckIframe) {
33
+ const iframe = this.iframes?.first
34
+ ?.nativeElement;
35
+ if (iframe) {
36
+ this.shouldCheckIframe = false;
37
+ this.reloadIframe(iframe);
38
+ }
39
+ }
40
+ }
41
+ ngOnDestroy() {
42
+ if (this.checkIFrameSubscription) {
43
+ this.checkIFrameSubscription.unsubscribe();
44
+ }
45
+ }
46
+ async ngOnChanges(changes) {
47
+ if (changes &&
48
+ changes['viewer'] &&
49
+ (changes['viewer'].isFirstChange ||
50
+ changes['viewer'].currentValue !== changes['viewer'].previousValue)) {
51
+ if (this.viewer !== 'google' &&
52
+ this.viewer !== 'office' &&
53
+ this.viewer !== 'mammoth' &&
54
+ this.viewer !== 'pdf' &&
55
+ this.viewer !== 'url') {
56
+ console.error(`Unsupported viewer: '${this.viewer}'. Supported viewers: google, office, mammoth and pdf`);
57
+ }
58
+ this.configuredViewer = this.viewer;
59
+ }
60
+ if ((changes['url'] && changes['url'].currentValue !== changes['url'].previousValue) ||
61
+ (changes['viewer'] &&
62
+ changes['viewer'].currentValue !== changes['viewer'].previousValue) ||
63
+ (changes['viewerUrl'] &&
64
+ changes['viewerUrl'].currentValue !== changes['viewerUrl'].previousValue)) {
65
+ let viewerDetails = getViewerDetails(this.url, this.configuredViewer, this.queryParams, this.viewerUrl);
66
+ this.externalViewer = viewerDetails.externalViewer;
67
+ if (viewerDetails.externalViewer && this.overrideLocalhost && isLocalFile(this.url)) {
68
+ const newUrl = replaceLocalUrl(this.url, this.overrideLocalhost);
69
+ viewerDetails = getViewerDetails(newUrl, this.configuredViewer, this.queryParams, this.viewerUrl);
70
+ }
71
+ this.docHtml = '';
72
+ if (this.checkIFrameSubscription) {
73
+ this.checkIFrameSubscription.unsubscribe();
74
+ }
75
+ if (!this.url) {
76
+ this.fullUrl = undefined;
77
+ }
78
+ else if (viewerDetails.externalViewer ||
79
+ this.configuredViewer === 'url') {
80
+ this.fullUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(viewerDetails.url);
81
+ // see:
82
+ // https://stackoverflow.com/questions/40414039/google-docs-viewer-returning-204-responses-no-longer-working-alternatives
83
+ // hack to reload iframe if it's not loaded.
84
+ // would maybe be better to use view.officeapps.live.com but seems not to work with sas token.
85
+ if (this.configuredViewer === 'google' &&
86
+ this.googleCheckContentLoaded) {
87
+ this.ngZone.runOutsideAngular(() => {
88
+ // if it's not loaded after the googleIntervalCheck, then open load again.
89
+ const iframe = this.iframes?.first
90
+ ?.nativeElement;
91
+ if (iframe) {
92
+ this.reloadIframe(iframe);
93
+ }
94
+ else {
95
+ this.shouldCheckIframe = true;
96
+ }
97
+ });
98
+ }
99
+ }
100
+ else if (this.configuredViewer === 'mammoth') {
101
+ this.docHtml = await getDocxToHtml(this.url);
102
+ }
103
+ }
104
+ }
105
+ reloadIframe(iframe) {
106
+ this.checkIFrameSubscription = googleCheckSubscription();
107
+ this.checkIFrameSubscription.subscribe(iframe, this.googleCheckInterval, this.googleMaxChecks);
108
+ }
109
+ iframeLoaded() {
110
+ const iframe = this.iframes?.first
111
+ ?.nativeElement;
112
+ if (iframe && iframeIsLoaded(iframe)) {
113
+ this.loaded.emit(undefined);
114
+ if (this.checkIFrameSubscription) {
115
+ this.checkIFrameSubscription.unsubscribe();
116
+ }
117
+ }
118
+ }
119
+ }
120
+ NgxDocViewerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
121
+ NgxDocViewerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: NgxDocViewerComponent, selector: "ngx-doc-viewer", inputs: { url: "url", queryParams: "queryParams", viewerUrl: "viewerUrl", googleCheckInterval: "googleCheckInterval", googleMaxChecks: "googleMaxChecks", disableContent: "disableContent", googleCheckContentLoaded: "googleCheckContentLoaded", viewer: "viewer", overrideLocalhost: "overrideLocalhost" }, outputs: { loaded: "loaded" }, viewQueries: [{ propertyName: "iframes", predicate: ["iframe"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block}.container{width:100%;height:100%;position:relative}.overlay-popout-google{width:40px;height:40px;right:26px;top:11.5px;position:absolute;z-index:1000}.overlay-popout-office{width:100px;height:20px;right:0;bottom:0;position:absolute;z-index:1000}.overlay-full{width:100%;height:100%;right:0;top:0;position:absolute;z-index:1000}iframe{width:100%;height:100%}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
122
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerComponent, decorators: [{
123
+ type: Component,
124
+ args: [{ selector: 'ngx-doc-viewer', styles: [
125
+ `
126
+ :host {
127
+ display: block;
128
+ }
129
+ .container {
130
+ width: 100%;
131
+ height: 100%;
132
+ position: relative;
133
+ }
134
+ .overlay-popout-google {
135
+ width: 40px;
136
+ height: 40px;
137
+ right: 26px;
138
+ top: 11.5px;
139
+ position: absolute;
140
+ z-index: 1000;
141
+ }
142
+ .overlay-popout-office {
143
+ width: 100px;
144
+ height: 20px;
145
+ right: 0;
146
+ bottom: 0;
147
+ position: absolute;
148
+ z-index: 1000;
149
+ }
150
+ .overlay-full {
151
+ width: 100%;
152
+ height: 100%;
153
+ right: 0;
154
+ top: 0;
155
+ position: absolute;
156
+ z-index: 1000;
157
+ }
158
+ iframe {
159
+ width: 100%;
160
+ height: 100%;
161
+ }
162
+ `,
163
+ ], template: "<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n" }]
164
+ }], ctorParameters: function () { return [{ type: i1.DomSanitizer }, { type: i0.NgZone }]; }, propDecorators: { loaded: [{
165
+ type: Output
166
+ }], url: [{
167
+ type: Input
168
+ }], queryParams: [{
169
+ type: Input
170
+ }], viewerUrl: [{
171
+ type: Input
172
+ }], googleCheckInterval: [{
173
+ type: Input
174
+ }], googleMaxChecks: [{
175
+ type: Input
176
+ }], disableContent: [{
177
+ type: Input
178
+ }], googleCheckContentLoaded: [{
179
+ type: Input
180
+ }], viewer: [{
181
+ type: Input
182
+ }], overrideLocalhost: [{
183
+ type: Input
184
+ }], iframes: [{
185
+ type: ViewChildren,
186
+ args: ['iframe']
187
+ }] } });
188
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdW1lbnQtdmlld2VyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL25neC1kb2Mtdmlld2VyL3NyYy9saWIvZG9jdW1lbnQtdmlld2VyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL25neC1kb2Mtdmlld2VyL3NyYy9saWIvZG9jdW1lbnQtdmlld2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFJTixNQUFNLEVBQ04sWUFBWSxFQUNaLFNBQVMsR0FHVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFtQixNQUFNLDJCQUEyQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0MsOERBQThEO0FBQzlELE9BQU8sRUFDTCxhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLHVCQUF1QixFQUN2QixjQUFjLEVBQ2QsV0FBVyxFQUNYLGVBQWUsRUFFaEIsTUFBTSxlQUFlLENBQUM7Ozs7QUFpRHZCLE1BQU0sT0FBTyxxQkFBcUI7SUFvQmhDLFlBQW9CLFlBQTBCLEVBQVUsTUFBYztRQUFsRCxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUFVLFdBQU0sR0FBTixNQUFNLENBQVE7UUFuQjVELFdBQU0sR0FBdUIsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNqRCxRQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ1QsZ0JBQVcsR0FBRyxFQUFFLENBQUM7UUFDakIsY0FBUyxHQUFHLEVBQUUsQ0FBQztRQUNmLHdCQUFtQixHQUFHLElBQUksQ0FBQztRQUMzQixvQkFBZSxHQUFHLENBQUMsQ0FBQztRQUNwQixtQkFBYyxHQUE4QyxNQUFNLENBQUM7UUFDbkUsNkJBQXdCLEdBQUcsSUFBSSxDQUFDO1FBQ2hDLFdBQU0sR0FBZSxRQUFR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ImltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIElucHV0LFxyXG4gIE5nWm9uZSxcclxuICBPbkRlc3Ryb3ksXHJcbiAgT25DaGFuZ2VzLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbiAgT3V0cHV0LFxyXG4gIFZpZXdDaGlsZHJlbixcclxuICBRdWVyeUxpc3QsXHJcbiAgRWxlbWVudFJlZixcclxuICBBZnRlclZpZXdJbml0LFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIsIFNhZmVSZXNvdXJjZVVybCB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xyXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBucndsL254L2VuZm9yY2UtbW9kdWxlLWJvdW5kYXJpZXNcclxuaW1wb3J0IHtcclxuICBnZXREb2N4VG9IdG1sLFxyXG4gIGdldFZpZXdlckRldGFpbHMsXHJcbiAgZ29vZ2xlQ2hlY2tTdWJzY3JpcHRpb24sXHJcbiAgaWZyYW1lSXNMb2FkZWQsXHJcbiAgaXNMb2NhbEZpbGUsXHJcbiAgcmVwbGFjZUxvY2FsVXJsLFxyXG4gIElGcmFtZVJlbG9hZGVyXHJcbn0gZnJvbSAnZG9jdmlld2hlbHBlcic7XHJcblxyXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25hbWluZy1jb252ZW50aW9uXHJcbmV4cG9ydCB0eXBlIHZpZXdlclR5cGUgPSAnZ29vZ2xlJyB8ICdvZmZpY2UnIHwgJ21hbW1vdGgnIHwgJ3BkZicgfCAndXJsJztcclxuQENvbXBvbmVudCh7XHJcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9jb21wb25lbnQtc2VsZWN0b3JcclxuICBzZWxlY3RvcjogJ25neC1kb2Mtdmlld2VyJyxcclxuICB0ZW1wbGF0ZVVybDogJ2RvY3VtZW50LXZpZXdlci5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVzOiBbXHJcbiAgICBgXHJcbiAgICAgIDpob3N0IHtcclxuICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgfVxyXG4gICAgICAuY29udGFpbmVyIHtcclxuICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgICB9XHJcbiAgICAgIC5vdmVybGF5LXBvcG91dC1nb29nbGUge1xyXG4gICAgICAgIHdpZHRoOiA0MHB4O1xyXG4gICAgICAgIGhlaWdodDogNDBweDtcclxuICAgICAgICByaWdodDogMjZweDtcclxuICAgICAgICB0b3A6IDExLjVweDtcclxuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgei1pbmRleDogMTAwMDtcclxuICAgICAgfVxyXG4gICAgICAub3ZlcmxheS1wb3BvdXQtb2ZmaWNlIHtcclxuICAgICAgICB3aWR0aDogMTAwcHg7XHJcbiAgICAgICAgaGVpZ2h0OiAyMHB4O1xyXG4gICAgICAgIHJpZ2h0OiAwO1xyXG4gICAgICAgIGJvdHRvbTogMDtcclxuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgei1pbmRleDogMTAwMDtcclxuICAgICAgfVxyXG4gICAgICAub3ZlcmxheS1mdWxsIHtcclxuICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICBoZWlnaHQ6IDEwMCU7XHJcbiAgICAgICAgcmlnaHQ6IDA7XHJcbiAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICB6LWluZGV4OiAxMDAwO1xyXG4gICAgICB9XHJcbiAgICAgIGlmcmFtZSB7XHJcbiAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICB9XHJcbiAgICBgLFxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ3hEb2NWaWV3ZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSwgQWZ0ZXJWaWV3SW5pdCB7XHJcbiAgQE91dHB1dCgpIGxvYWRlZDogRXZlbnRFbWl0dGVyPHZvaWQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG4gIEBJbnB1dCgpIHVybCA9ICcnO1xyXG4gIEBJbnB1dCgpIHF1ZXJ5UGFyYW1zID0gJyc7XHJcbiAgQElucHV0KCkgdmlld2VyVXJsID0gJyc7XHJcbiAgQElucHV0KCkgZ29vZ2xlQ2hlY2tJbnRlcnZhbCA9IDMwMDA7XHJcbiAgQElucHV0KCkgZ29vZ2xlTWF4Q2hlY2tzID0gNTtcclxuICBASW5wdXQoKSBkaXNhYmxlQ29udGVudDogJ25vbmUnIHwgJ2FsbCcgfCAncG9wb3V0JyB8ICdwb3BvdXQtaGlkZScgPSAnbm9uZSc7XHJcbiAgQElucHV0KCkgZ29vZ2xlQ2hlY2tDb250ZW50TG9hZGVkID0gdHJ1ZTtcclxuICBASW5wdXQoKSB2aWV3ZXI6IHZpZXdlclR5cGUgPSAnZ29vZ2xlJztcclxuICBASW5wdXQoKSBvdmVycmlkZUxvY2FsaG9zdCA9ICcnO1xyXG4gIEBWaWV3Q2hpbGRyZW4oJ2lmcmFtZScpIGlmcmFtZXM/OiBRdWVyeUxpc3Q8RWxlbWVudFJlZj4gPSB1bmRlZmluZWQ7XHJcblxyXG4gIHB1YmxpYyBmdWxsVXJsPzogU2FmZVJlc291cmNlVXJsID0gdW5kZWZpbmVkO1xyXG4gIHB1YmxpYyBleHRlcm5hbFZpZXdlciA9IGZhbHNlO1xyXG4gIHB1YmxpYyBkb2NIdG1sID0gJyc7XHJcbiAgcHVibGljIGNvbmZpZ3VyZWRWaWV3ZXI6IHZpZXdlclR5cGUgPSAnZ29vZ2xlJztcclxuICBwcml2YXRlIGNoZWNrSUZyYW1lU3Vic2NyaXB0aW9uPzogSUZyYW1lUmVsb2FkZXIgPSB1bmRlZmluZWQ7XHJcbiAgcHJpdmF0ZSBzaG91bGRDaGVja0lmcmFtZSA9IGZhbHNlO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGRvbVNhbml0aXplcjogRG9tU2FuaXRpemVyLCBwcml2YXRlIG5nWm9uZTogTmdab25lKSB7IH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuc2hvdWxkQ2hlY2tJZnJhbWUpIHtcclxuICAgICAgY29uc3QgaWZyYW1lID0gdGhpcy5pZnJhbWVzPy5maXJzdFxyXG4gICAgICAgID8ubmF0aXZlRWxlbWVudCBhcyBIVE1MSUZyYW1lRWxlbWVudDtcclxuICAgICAgaWYgKGlmcmFtZSkge1xyXG4gICAgICAgIHRoaXMuc2hvdWxkQ2hlY2tJZnJhbWUgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLnJlbG9hZElmcmFtZShpZnJhbWUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmNoZWNrSUZyYW1lU3Vic2NyaXB0aW9uKSB7XHJcbiAgICAgIHRoaXMuY2hlY2tJRnJhbWVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGFzeW5jIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGlmIChcclxuICAgICAgY2hhbmdlcyAmJlxyXG4gICAgICBjaGFuZ2VzWyd2aWV3ZXInXSAmJlxyXG4gICAgICAoY2hhbmdlc1sndmlld2VyJ10uaXNGaXJzdENoYW5nZSB8fFxyXG4gICAgICAgIGNoYW5nZXNbJ3ZpZXdlciddLmN1cnJlbnRWYWx1ZSAhPT0gY2hhbmdlc1sndmlld2VyJ10ucHJldmlvdXNWYWx1ZSlcclxuICAgICkge1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgdGhpcy52aWV3ZXIgIT09ICdnb29nbGUnICYmXHJcbiAgICAgICAgdGhpcy52aWV3ZXIgIT09ICdvZmZpY2UnICYmXHJcbiAgICAgICAgdGhpcy52aWV3ZXIgIT09ICdtYW1tb3RoJyAmJlxyXG4gICAgICAgIHRoaXMudmlld2VyICE9PSAncGRmJyAmJlxyXG4gICAgICAgIHRoaXMudmlld2VyICE9PSAndXJsJ1xyXG4gICAgICApIHtcclxuICAgICAgICBjb25zb2xlLmVycm9yKFxyXG4gICAgICAgICAgYFVuc3VwcG9ydGVkIHZpZXdlcjogJyR7dGhpcy52aWV3ZXJ9Jy4gU3VwcG9ydGVkIHZpZXdlcnM6IGdvb2dsZSwgb2ZmaWNlLCBtYW1tb3RoIGFuZCBwZGZgXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmNvbmZpZ3VyZWRWaWV3ZXIgPSB0aGlzLnZpZXdlcjtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIChjaGFuZ2VzWyd1cmwnXSAmJiBjaGFuZ2VzWyd1cmwnXS5jdXJyZW50VmFsdWUgIT09IGNoYW5nZXNbJ3VybCddLnByZXZpb3VzVmFsdWUpIHx8XHJcbiAgICAgIChjaGFuZ2VzWyd2aWV3ZXInXSAmJlxyXG4gICAgICAgIGNoYW5nZXNbJ3ZpZXdlciddLmN1cnJlbnRWYWx1ZSAhPT0gY2hhbmdlc1sndmlld2VyJ10ucHJldmlvdXNWYWx1ZSkgfHxcclxuICAgICAgKGNoYW5nZXNbJ3ZpZXdlclVybCddICYmXHJcbiAgICAgICAgY2hhbmdlc1sndmlld2VyVXJsJ10uY3VycmVudFZhbHVlICE9PSBjaGFuZ2VzWyd2aWV3ZXJVcmwnXS5wcmV2aW91c1ZhbHVlKVxyXG4gICAgKSB7XHJcbiAgICAgIGxldCB2aWV3ZXJEZXRhaWxzID0gZ2V0Vmlld2VyRGV0YWlscyhcclxuICAgICAgICB0aGlzLnVybCxcclxuICAgICAgICB0aGlzLmNvbmZpZ3VyZWRWaWV3ZXIsXHJcbiAgICAgICAgdGhpcy5xdWVyeVBhcmFtcyxcclxuICAgICAgICB0aGlzLnZpZXdlclVybFxyXG4gICAgICApO1xyXG4gICAgICB0aGlzLmV4dGVybmFsVmlld2VyID0gdmlld2VyRGV0YWlscy5leHRlcm5hbFZpZXdlcjtcclxuICAgICAgaWYgKHZpZXdlckRldGFpbHMuZXh0ZXJuYWxWaWV3ZXIgJiYgdGhpcy5vdmVycmlkZUxvY2FsaG9zdCAmJiBpc0xvY2FsRmlsZSh0aGlzLnVybCkpIHtcclxuICAgICAgICBjb25zdCBuZXdVcmwgPSByZXBsYWNlTG9jYWxVcmwodGhpcy51cmwsIHRoaXMub3ZlcnJpZGVMb2NhbGhvc3QpO1xyXG4gICAgICAgIHZpZXdlckRldGFpbHMgPSBnZXRWaWV3ZXJEZXRhaWxzKFxyXG4gICAgICAgICAgbmV3VXJsLFxyXG4gICAgICAgICAgdGhpcy5jb25maWd1cmVkVmlld2VyLFxyXG4gICAgICAgICAgdGhpcy5xdWVyeVBhcmFtcyxcclxuICAgICAgICAgIHRoaXMudmlld2VyVXJsXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmRvY0h0bWwgPSAnJztcclxuICAgICAgaWYgKHRoaXMuY2hlY2tJRnJhbWVTdWJzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLmNoZWNrSUZyYW1lU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKCF0aGlzLnVybCkge1xyXG4gICAgICAgIHRoaXMuZnVsbFVybCA9IHVuZGVmaW5lZDtcclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICB2aWV3ZXJEZXRhaWxzLmV4dGVybmFsVmlld2VyIHx8XHJcbiAgICAgICAgdGhpcy5jb25maWd1cmVkVmlld2VyID09PSAndXJsJ1xyXG4gICAgICApIHtcclxuICAgICAgICB0aGlzLmZ1bGxVcmwgPSB0aGlzLmRvbVNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0UmVzb3VyY2VVcmwoXHJcbiAgICAgICAgICB2aWV3ZXJEZXRhaWxzLnVybFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgLy8gc2VlOlxyXG4gICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQwNDE0MDM5L2dvb2dsZS1kb2NzLXZpZXdlci1yZXR1cm5pbmctMjA0LXJlc3BvbnNlcy1uby1sb25nZXItd29ya2luZy1hbHRlcm5hdGl2ZXNcclxuICAgICAgICAvLyBoYWNrIHRvIHJlbG9hZCBpZnJhbWUgaWYgaXQncyBub3QgbG9hZGVkLlxyXG4gICAgICAgIC8vIHdvdWxkIG1heWJlIGJlIGJldHRlciB0byB1c2Ugdmlldy5vZmZpY2VhcHBzLmxpdmUuY29tIGJ1dCBzZWVtcyBub3QgdG8gd29yayB3aXRoIHNhcyB0b2tlbi5cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0aGlzLmNvbmZpZ3VyZWRWaWV3ZXIgPT09ICdnb29nbGUnICYmXHJcbiAgICAgICAgICB0aGlzLmdvb2dsZUNoZWNrQ29udGVudExvYWRlZFxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAgICAgICAvLyBpZiBpdCdzIG5vdCBsb2FkZWQgYWZ0ZXIgdGhlIGdvb2dsZUludGVydmFsQ2hlY2ssIHRoZW4gb3BlbiBsb2FkIGFnYWluLlxyXG4gICAgICAgICAgICBjb25zdCBpZnJhbWUgPSB0aGlzLmlmcmFtZXM/LmZpcnN0XHJcbiAgICAgICAgICAgICAgPy5uYXRpdmVFbGVtZW50IGFzIEhUTUxJRnJhbWVFbGVtZW50O1xyXG4gICAgICAgICAgICBpZiAoaWZyYW1lKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5yZWxvYWRJZnJhbWUoaWZyYW1lKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICB0aGlzLnNob3VsZENoZWNrSWZyYW1lID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKHRoaXMuY29uZmlndXJlZFZpZXdlciA9PT0gJ21hbW1vdGgnKSB7XHJcbiAgICAgICAgdGhpcy5kb2NIdG1sID0gYXdhaXQgZ2V0RG9jeFRvSHRtbCh0aGlzLnVybCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVsb2FkSWZyYW1lKGlmcmFtZTogSFRNTElGcmFtZUVsZW1lbnQpIHtcclxuICAgIHRoaXMuY2hlY2tJRnJhbWVTdWJzY3JpcHRpb24gPSBnb29nbGVDaGVja1N1YnNjcmlwdGlvbigpO1xyXG4gICAgdGhpcy5jaGVja0lGcmFtZVN1YnNjcmlwdGlvbi5zdWJzY3JpYmUoXHJcbiAgICAgIGlmcmFtZSxcclxuICAgICAgdGhpcy5nb29nbGVDaGVja0ludGVydmFsLFxyXG4gICAgICB0aGlzLmdvb2dsZU1heENoZWNrc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIGlmcmFtZUxvYWRlZCgpIHtcclxuICAgIGNvbnN0IGlmcmFtZSA9IHRoaXMuaWZyYW1lcz8uZmlyc3RcclxuICAgICAgPy5uYXRpdmVFbGVtZW50IGFzIEhUTUxJRnJhbWVFbGVtZW50O1xyXG4gICAgaWYgKGlmcmFtZSAmJiBpZnJhbWVJc0xvYWRlZChpZnJhbWUpKSB7XHJcbiAgICAgIHRoaXMubG9hZGVkLmVtaXQodW5kZWZpbmVkKTtcclxuICAgICAgaWYgKHRoaXMuY2hlY2tJRnJhbWVTdWJzY3JpcHRpb24pIHtcclxuICAgICAgICB0aGlzLmNoZWNrSUZyYW1lU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFleHRlcm5hbFZpZXdlclwiPlxyXG4gIDxkaXYgKm5nSWY9XCJjb25maWd1cmVkVmlld2VyICE9PSAncGRmJ1wiIFtpbm5lckh0bWxdPVwiZG9jSHRtbFwiPjwvZGl2PlxyXG4gIDxvYmplY3RcclxuICAgICpuZ0lmPVwiZnVsbFVybCAmJiBjb25maWd1cmVkVmlld2VyID09PSAncGRmJ1wiXHJcbiAgICBbZGF0YV09XCJmdWxsVXJsXCJcclxuICAgIHR5cGU9XCJhcHBsaWNhdGlvbi9wZGZcIlxyXG4gICAgd2lkdGg9XCIxMDAlXCJcclxuICAgIGhlaWdodD1cIjEwMCVcIlxyXG4gID5cclxuICAgIDxwPlxyXG4gICAgICBZb3VyIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBQREZzLlxyXG4gICAgICA8YSBbaHJlZl09XCJmdWxsVXJsXCI+RG93bmxvYWQgdGhlIFBERjwvYT4uXHJcbiAgICA8L3A+XHJcbiAgPC9vYmplY3Q+XHJcbjwvbmctY29udGFpbmVyPlxyXG48bmctY29udGFpbmVyICpuZ0lmPVwiZXh0ZXJuYWxWaWV3ZXJcIj5cclxuICA8aWZyYW1lXHJcbiAgICAobG9hZCk9XCJpZnJhbWVMb2FkZWQoKVwiXHJcbiAgICAqbmdJZj1cImZ1bGxVcmwgJiYgZGlzYWJsZUNvbnRlbnQgPT09ICdub25lJ1wiXHJcbiAgICAjaWZyYW1lXHJcbiAgICBpZD1cImlmcmFtZS1kb2Mtdmlld2VyXCJcclxuICAgIGZyYW1lQm9yZGVyPVwiMFwiXHJcbiAgICBbc3JjXT1cImZ1bGxVcmxcIlxyXG4gID48L2lmcmFtZT5cclxuICA8ZGl2IGNsYXNzPVwiY29udGFpbmVyXCIgKm5nSWY9XCJkaXNhYmxlQ29udGVudCAhPT0gJ25vbmUnXCI+XHJcbiAgICA8ZGl2XHJcbiAgICAgIFtjbGFzcy5vdmVybGF5LWZ1bGxdPVwiZGlzYWJsZUNvbnRlbnQgPT09ICdhbGwnXCJcclxuICAgICAgW2NsYXNzLm92ZXJsYXktcG9wb3V0LWdvb2dsZV09XCJcclxuICAgICAgICBjb25maWd1cmVkVmlld2VyID09PSAnZ29vZ2xlJyAmJlxyXG4gICAgICAgIChkaXNhYmxlQ29udGVudCA9PT0gJ3BvcG91dCcgfHwgZGlzYWJsZUNvbnRlbnQgPT09ICdwb3BvdXQtaGlkZScpXHJcbiAgICAgIFwiXHJcbiAgICAgIFtjbGFzcy5vdmVybGF5LXBvcG91dC1vZmZpY2VdPVwiXHJcbiAgICAgICAgY29uZmlndXJlZFZpZXdlciA9PT0gJ29mZmljZScgJiZcclxuICAgICAgICAoZGlzYWJsZUNvbnRlbnQgPT09ICdwb3BvdXQnIHx8IGRpc2FibGVDb250ZW50ID09PSAncG9wb3V0LWhpZGUnKVxyXG4gICAgICBcIlxyXG4gICAgICBbc3R5bGUuYmFja2dyb3VuZC1jb2xvcl09XCJcclxuICAgICAgICBkaXNhYmxlQ29udGVudCA9PT0gJ3BvcG91dC1oaWRlJyA/ICcjZmZmJyA6ICd0cmFuc3BhcmVudCdcclxuICAgICAgXCJcclxuICAgID48L2Rpdj5cclxuICAgIDxpZnJhbWVcclxuICAgICAgKGxvYWQpPVwiaWZyYW1lTG9hZGVkKClcIlxyXG4gICAgICAqbmdJZj1cImZ1bGxVcmxcIlxyXG4gICAgICAjaWZyYW1lXHJcbiAgICAgIGlkPVwiaWZyYW1lXCJcclxuICAgICAgZnJhbWVCb3JkZXI9XCIwXCJcclxuICAgICAgW3NyY109XCJmdWxsVXJsXCJcclxuICAgID48L2lmcmFtZT5cclxuICA8L2Rpdj5cclxuPC9uZy1jb250YWluZXI+XHJcbiJdfQ==
@@ -0,0 +1,18 @@
1
+ import { NgxDocViewerComponent } from './document-viewer.component';
2
+ import { NgModule } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i0 from "@angular/core";
5
+ export class NgxDocViewerModule {
6
+ }
7
+ NgxDocViewerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
8
+ NgxDocViewerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, declarations: [NgxDocViewerComponent], imports: [CommonModule], exports: [NgxDocViewerComponent] });
9
+ NgxDocViewerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, imports: [[CommonModule]] });
10
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, decorators: [{
11
+ type: NgModule,
12
+ args: [{
13
+ imports: [CommonModule],
14
+ declarations: [NgxDocViewerComponent],
15
+ exports: [NgxDocViewerComponent],
16
+ }]
17
+ }] });
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdW1lbnQtdmlld2VyLm1vZHVsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL25neC1kb2Mtdmlld2VyL3NyYy9saWIvZG9jdW1lbnQtdmlld2VyLm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7QUFPL0MsTUFBTSxPQUFPLGtCQUFrQjs7K0dBQWxCLGtCQUFrQjtnSEFBbEIsa0JBQWtCLGlCQUhkLHFCQUFxQixhQUQxQixZQUFZLGFBRVoscUJBQXFCO2dIQUVwQixrQkFBa0IsWUFKcEIsQ0FBQyxZQUFZLENBQUM7MkZBSVosa0JBQWtCO2tCQUw5QixRQUFRO21CQUFDO29CQUNSLE9BQU8sRUFBRSxDQUFDLFlBQVksQ0FBQztvQkFDdkIsWUFBWSxFQUFFLENBQUMscUJBQXFCLENBQUM7b0JBQ3JDLE9BQU8sRUFBRSxDQUFDLHFCQUFxQixDQUFDO2lCQUNqQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5neERvY1ZpZXdlckNvbXBvbmVudCB9IGZyb20gJy4vZG9jdW1lbnQtdmlld2VyLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcblxyXG5ATmdNb2R1bGUoe1xyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIGRlY2xhcmF0aW9uczogW05neERvY1ZpZXdlckNvbXBvbmVudF0sXHJcbiAgZXhwb3J0czogW05neERvY1ZpZXdlckNvbXBvbmVudF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ3hEb2NWaWV3ZXJNb2R1bGUge31cclxuIl19
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWRvYy12aWV3ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wYWNrYWdlcy9uZ3gtZG9jLXZpZXdlci9zcmMvbmd4LWRvYy12aWV3ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0=
@@ -0,0 +1,211 @@
1
+ import { __awaiter } from 'tslib';
2
+ import * as i0 from '@angular/core';
3
+ import { EventEmitter, Component, Output, Input, ViewChildren, NgModule } from '@angular/core';
4
+ import { getViewerDetails, isLocalFile, replaceLocalUrl, getDocxToHtml, googleCheckSubscription, iframeIsLoaded } from 'docviewhelper';
5
+ export * from 'docviewhelper';
6
+ import * as i1 from '@angular/platform-browser';
7
+ import * as i2 from '@angular/common';
8
+ import { CommonModule } from '@angular/common';
9
+
10
+ class NgxDocViewerComponent {
11
+ constructor(domSanitizer, ngZone) {
12
+ this.domSanitizer = domSanitizer;
13
+ this.ngZone = ngZone;
14
+ this.loaded = new EventEmitter();
15
+ this.url = '';
16
+ this.queryParams = '';
17
+ this.viewerUrl = '';
18
+ this.googleCheckInterval = 3000;
19
+ this.googleMaxChecks = 5;
20
+ this.disableContent = 'none';
21
+ this.googleCheckContentLoaded = true;
22
+ this.viewer = 'google';
23
+ this.overrideLocalhost = '';
24
+ this.iframes = undefined;
25
+ this.fullUrl = undefined;
26
+ this.externalViewer = false;
27
+ this.docHtml = '';
28
+ this.configuredViewer = 'google';
29
+ this.checkIFrameSubscription = undefined;
30
+ this.shouldCheckIframe = false;
31
+ }
32
+ ngAfterViewInit() {
33
+ var _a, _b;
34
+ if (this.shouldCheckIframe) {
35
+ const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement;
36
+ if (iframe) {
37
+ this.shouldCheckIframe = false;
38
+ this.reloadIframe(iframe);
39
+ }
40
+ }
41
+ }
42
+ ngOnDestroy() {
43
+ if (this.checkIFrameSubscription) {
44
+ this.checkIFrameSubscription.unsubscribe();
45
+ }
46
+ }
47
+ ngOnChanges(changes) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ if (changes &&
50
+ changes['viewer'] &&
51
+ (changes['viewer'].isFirstChange ||
52
+ changes['viewer'].currentValue !== changes['viewer'].previousValue)) {
53
+ if (this.viewer !== 'google' &&
54
+ this.viewer !== 'office' &&
55
+ this.viewer !== 'mammoth' &&
56
+ this.viewer !== 'pdf' &&
57
+ this.viewer !== 'url') {
58
+ console.error(`Unsupported viewer: '${this.viewer}'. Supported viewers: google, office, mammoth and pdf`);
59
+ }
60
+ this.configuredViewer = this.viewer;
61
+ }
62
+ if ((changes['url'] && changes['url'].currentValue !== changes['url'].previousValue) ||
63
+ (changes['viewer'] &&
64
+ changes['viewer'].currentValue !== changes['viewer'].previousValue) ||
65
+ (changes['viewerUrl'] &&
66
+ changes['viewerUrl'].currentValue !== changes['viewerUrl'].previousValue)) {
67
+ let viewerDetails = getViewerDetails(this.url, this.configuredViewer, this.queryParams, this.viewerUrl);
68
+ this.externalViewer = viewerDetails.externalViewer;
69
+ if (viewerDetails.externalViewer && this.overrideLocalhost && isLocalFile(this.url)) {
70
+ const newUrl = replaceLocalUrl(this.url, this.overrideLocalhost);
71
+ viewerDetails = getViewerDetails(newUrl, this.configuredViewer, this.queryParams, this.viewerUrl);
72
+ }
73
+ this.docHtml = '';
74
+ if (this.checkIFrameSubscription) {
75
+ this.checkIFrameSubscription.unsubscribe();
76
+ }
77
+ if (!this.url) {
78
+ this.fullUrl = undefined;
79
+ }
80
+ else if (viewerDetails.externalViewer ||
81
+ this.configuredViewer === 'url') {
82
+ this.fullUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(viewerDetails.url);
83
+ // see:
84
+ // https://stackoverflow.com/questions/40414039/google-docs-viewer-returning-204-responses-no-longer-working-alternatives
85
+ // hack to reload iframe if it's not loaded.
86
+ // would maybe be better to use view.officeapps.live.com but seems not to work with sas token.
87
+ if (this.configuredViewer === 'google' &&
88
+ this.googleCheckContentLoaded) {
89
+ this.ngZone.runOutsideAngular(() => {
90
+ var _a, _b;
91
+ // if it's not loaded after the googleIntervalCheck, then open load again.
92
+ const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement;
93
+ if (iframe) {
94
+ this.reloadIframe(iframe);
95
+ }
96
+ else {
97
+ this.shouldCheckIframe = true;
98
+ }
99
+ });
100
+ }
101
+ }
102
+ else if (this.configuredViewer === 'mammoth') {
103
+ this.docHtml = yield getDocxToHtml(this.url);
104
+ }
105
+ }
106
+ });
107
+ }
108
+ reloadIframe(iframe) {
109
+ this.checkIFrameSubscription = googleCheckSubscription();
110
+ this.checkIFrameSubscription.subscribe(iframe, this.googleCheckInterval, this.googleMaxChecks);
111
+ }
112
+ iframeLoaded() {
113
+ var _a, _b;
114
+ const iframe = (_b = (_a = this.iframes) === null || _a === void 0 ? void 0 : _a.first) === null || _b === void 0 ? void 0 : _b.nativeElement;
115
+ if (iframe && iframeIsLoaded(iframe)) {
116
+ this.loaded.emit(undefined);
117
+ if (this.checkIFrameSubscription) {
118
+ this.checkIFrameSubscription.unsubscribe();
119
+ }
120
+ }
121
+ }
122
+ }
123
+ NgxDocViewerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
124
+ NgxDocViewerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: NgxDocViewerComponent, selector: "ngx-doc-viewer", inputs: { url: "url", queryParams: "queryParams", viewerUrl: "viewerUrl", googleCheckInterval: "googleCheckInterval", googleMaxChecks: "googleMaxChecks", disableContent: "disableContent", googleCheckContentLoaded: "googleCheckContentLoaded", viewer: "viewer", overrideLocalhost: "overrideLocalhost" }, outputs: { loaded: "loaded" }, viewQueries: [{ propertyName: "iframes", predicate: ["iframe"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n", styles: [":host{display:block}.container{width:100%;height:100%;position:relative}.overlay-popout-google{width:40px;height:40px;right:26px;top:11.5px;position:absolute;z-index:1000}.overlay-popout-office{width:100px;height:20px;right:0;bottom:0;position:absolute;z-index:1000}.overlay-full{width:100%;height:100%;right:0;top:0;position:absolute;z-index:1000}iframe{width:100%;height:100%}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerComponent, decorators: [{
126
+ type: Component,
127
+ args: [{ selector: 'ngx-doc-viewer', styles: [
128
+ `
129
+ :host {
130
+ display: block;
131
+ }
132
+ .container {
133
+ width: 100%;
134
+ height: 100%;
135
+ position: relative;
136
+ }
137
+ .overlay-popout-google {
138
+ width: 40px;
139
+ height: 40px;
140
+ right: 26px;
141
+ top: 11.5px;
142
+ position: absolute;
143
+ z-index: 1000;
144
+ }
145
+ .overlay-popout-office {
146
+ width: 100px;
147
+ height: 20px;
148
+ right: 0;
149
+ bottom: 0;
150
+ position: absolute;
151
+ z-index: 1000;
152
+ }
153
+ .overlay-full {
154
+ width: 100%;
155
+ height: 100%;
156
+ right: 0;
157
+ top: 0;
158
+ position: absolute;
159
+ z-index: 1000;
160
+ }
161
+ iframe {
162
+ width: 100%;
163
+ height: 100%;
164
+ }
165
+ `,
166
+ ], template: "<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n" }]
167
+ }], ctorParameters: function () { return [{ type: i1.DomSanitizer }, { type: i0.NgZone }]; }, propDecorators: { loaded: [{
168
+ type: Output
169
+ }], url: [{
170
+ type: Input
171
+ }], queryParams: [{
172
+ type: Input
173
+ }], viewerUrl: [{
174
+ type: Input
175
+ }], googleCheckInterval: [{
176
+ type: Input
177
+ }], googleMaxChecks: [{
178
+ type: Input
179
+ }], disableContent: [{
180
+ type: Input
181
+ }], googleCheckContentLoaded: [{
182
+ type: Input
183
+ }], viewer: [{
184
+ type: Input
185
+ }], overrideLocalhost: [{
186
+ type: Input
187
+ }], iframes: [{
188
+ type: ViewChildren,
189
+ args: ['iframe']
190
+ }] } });
191
+
192
+ class NgxDocViewerModule {
193
+ }
194
+ NgxDocViewerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
195
+ NgxDocViewerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, declarations: [NgxDocViewerComponent], imports: [CommonModule], exports: [NgxDocViewerComponent] });
196
+ NgxDocViewerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, imports: [[CommonModule]] });
197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: NgxDocViewerModule, decorators: [{
198
+ type: NgModule,
199
+ args: [{
200
+ imports: [CommonModule],
201
+ declarations: [NgxDocViewerComponent],
202
+ exports: [NgxDocViewerComponent],
203
+ }]
204
+ }] });
205
+
206
+ /**
207
+ * Generated bundle index. Do not edit.
208
+ */
209
+
210
+ export { NgxDocViewerComponent, NgxDocViewerModule };
211
+ //# sourceMappingURL=ngx-doc-viewer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-doc-viewer.mjs","sources":["../../../../packages/ngx-doc-viewer/src/lib/document-viewer.component.ts","../../../../packages/ngx-doc-viewer/src/lib/document-viewer.component.html","../../../../packages/ngx-doc-viewer/src/lib/document-viewer.module.ts","../../../../packages/ngx-doc-viewer/src/ngx-doc-viewer.ts"],"sourcesContent":["import {\r\n Component,\r\n Input,\r\n NgZone,\r\n OnDestroy,\r\n OnChanges,\r\n SimpleChanges,\r\n Output,\r\n ViewChildren,\r\n QueryList,\r\n ElementRef,\r\n AfterViewInit,\r\n} from '@angular/core';\r\nimport { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';\r\nimport { EventEmitter } from '@angular/core';\r\n// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries\r\nimport {\r\n getDocxToHtml,\r\n getViewerDetails,\r\n googleCheckSubscription,\r\n iframeIsLoaded,\r\n isLocalFile,\r\n replaceLocalUrl,\r\n IFrameReloader\r\n} from 'docviewhelper';\r\n\r\n// eslint-disable-next-line @typescript-eslint/naming-convention\r\nexport type viewerType = 'google' | 'office' | 'mammoth' | 'pdf' | 'url';\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'ngx-doc-viewer',\r\n templateUrl: 'document-viewer.component.html',\r\n styles: [\r\n `\r\n :host {\r\n display: block;\r\n }\r\n .container {\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n }\r\n .overlay-popout-google {\r\n width: 40px;\r\n height: 40px;\r\n right: 26px;\r\n top: 11.5px;\r\n position: absolute;\r\n z-index: 1000;\r\n }\r\n .overlay-popout-office {\r\n width: 100px;\r\n height: 20px;\r\n right: 0;\r\n bottom: 0;\r\n position: absolute;\r\n z-index: 1000;\r\n }\r\n .overlay-full {\r\n width: 100%;\r\n height: 100%;\r\n right: 0;\r\n top: 0;\r\n position: absolute;\r\n z-index: 1000;\r\n }\r\n iframe {\r\n width: 100%;\r\n height: 100%;\r\n }\r\n `,\r\n ],\r\n})\r\nexport class NgxDocViewerComponent implements OnChanges, OnDestroy, AfterViewInit {\r\n @Output() loaded: EventEmitter<void> = new EventEmitter();\r\n @Input() url = '';\r\n @Input() queryParams = '';\r\n @Input() viewerUrl = '';\r\n @Input() googleCheckInterval = 3000;\r\n @Input() googleMaxChecks = 5;\r\n @Input() disableContent: 'none' | 'all' | 'popout' | 'popout-hide' = 'none';\r\n @Input() googleCheckContentLoaded = true;\r\n @Input() viewer: viewerType = 'google';\r\n @Input() overrideLocalhost = '';\r\n @ViewChildren('iframe') iframes?: QueryList<ElementRef> = undefined;\r\n\r\n public fullUrl?: SafeResourceUrl = undefined;\r\n public externalViewer = false;\r\n public docHtml = '';\r\n public configuredViewer: viewerType = 'google';\r\n private checkIFrameSubscription?: IFrameReloader = undefined;\r\n private shouldCheckIframe = false;\r\n\r\n constructor(private domSanitizer: DomSanitizer, private ngZone: NgZone) { }\r\n\r\n ngAfterViewInit(): void {\r\n if (this.shouldCheckIframe) {\r\n const iframe = this.iframes?.first\r\n ?.nativeElement as HTMLIFrameElement;\r\n if (iframe) {\r\n this.shouldCheckIframe = false;\r\n this.reloadIframe(iframe);\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n if (this.checkIFrameSubscription) {\r\n this.checkIFrameSubscription.unsubscribe();\r\n }\r\n }\r\n\r\n async ngOnChanges(changes: SimpleChanges): Promise<void> {\r\n if (\r\n changes &&\r\n changes['viewer'] &&\r\n (changes['viewer'].isFirstChange ||\r\n changes['viewer'].currentValue !== changes['viewer'].previousValue)\r\n ) {\r\n if (\r\n this.viewer !== 'google' &&\r\n this.viewer !== 'office' &&\r\n this.viewer !== 'mammoth' &&\r\n this.viewer !== 'pdf' &&\r\n this.viewer !== 'url'\r\n ) {\r\n console.error(\r\n `Unsupported viewer: '${this.viewer}'. Supported viewers: google, office, mammoth and pdf`\r\n );\r\n }\r\n this.configuredViewer = this.viewer;\r\n }\r\n\r\n if (\r\n (changes['url'] && changes['url'].currentValue !== changes['url'].previousValue) ||\r\n (changes['viewer'] &&\r\n changes['viewer'].currentValue !== changes['viewer'].previousValue) ||\r\n (changes['viewerUrl'] &&\r\n changes['viewerUrl'].currentValue !== changes['viewerUrl'].previousValue)\r\n ) {\r\n let viewerDetails = getViewerDetails(\r\n this.url,\r\n this.configuredViewer,\r\n this.queryParams,\r\n this.viewerUrl\r\n );\r\n this.externalViewer = viewerDetails.externalViewer;\r\n if (viewerDetails.externalViewer && this.overrideLocalhost && isLocalFile(this.url)) {\r\n const newUrl = replaceLocalUrl(this.url, this.overrideLocalhost);\r\n viewerDetails = getViewerDetails(\r\n newUrl,\r\n this.configuredViewer,\r\n this.queryParams,\r\n this.viewerUrl\r\n );\r\n }\r\n this.docHtml = '';\r\n if (this.checkIFrameSubscription) {\r\n this.checkIFrameSubscription.unsubscribe();\r\n }\r\n if (!this.url) {\r\n this.fullUrl = undefined;\r\n } else if (\r\n viewerDetails.externalViewer ||\r\n this.configuredViewer === 'url'\r\n ) {\r\n this.fullUrl = this.domSanitizer.bypassSecurityTrustResourceUrl(\r\n viewerDetails.url\r\n );\r\n // see:\r\n // https://stackoverflow.com/questions/40414039/google-docs-viewer-returning-204-responses-no-longer-working-alternatives\r\n // hack to reload iframe if it's not loaded.\r\n // would maybe be better to use view.officeapps.live.com but seems not to work with sas token.\r\n if (\r\n this.configuredViewer === 'google' &&\r\n this.googleCheckContentLoaded\r\n ) {\r\n this.ngZone.runOutsideAngular(() => {\r\n // if it's not loaded after the googleIntervalCheck, then open load again.\r\n const iframe = this.iframes?.first\r\n ?.nativeElement as HTMLIFrameElement;\r\n if (iframe) {\r\n this.reloadIframe(iframe);\r\n } else {\r\n this.shouldCheckIframe = true;\r\n }\r\n });\r\n }\r\n } else if (this.configuredViewer === 'mammoth') {\r\n this.docHtml = await getDocxToHtml(this.url);\r\n }\r\n }\r\n }\r\n\r\n private reloadIframe(iframe: HTMLIFrameElement) {\r\n this.checkIFrameSubscription = googleCheckSubscription();\r\n this.checkIFrameSubscription.subscribe(\r\n iframe,\r\n this.googleCheckInterval,\r\n this.googleMaxChecks\r\n );\r\n }\r\n\r\n iframeLoaded() {\r\n const iframe = this.iframes?.first\r\n ?.nativeElement as HTMLIFrameElement;\r\n if (iframe && iframeIsLoaded(iframe)) {\r\n this.loaded.emit(undefined);\r\n if (this.checkIFrameSubscription) {\r\n this.checkIFrameSubscription.unsubscribe();\r\n }\r\n }\r\n }\r\n}\r\n","<ng-container *ngIf=\"!externalViewer\">\r\n <div *ngIf=\"configuredViewer !== 'pdf'\" [innerHtml]=\"docHtml\"></div>\r\n <object\r\n *ngIf=\"fullUrl && configuredViewer === 'pdf'\"\r\n [data]=\"fullUrl\"\r\n type=\"application/pdf\"\r\n width=\"100%\"\r\n height=\"100%\"\r\n >\r\n <p>\r\n Your browser does not support PDFs.\r\n <a [href]=\"fullUrl\">Download the PDF</a>.\r\n </p>\r\n </object>\r\n</ng-container>\r\n<ng-container *ngIf=\"externalViewer\">\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl && disableContent === 'none'\"\r\n #iframe\r\n id=\"iframe-doc-viewer\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n <div class=\"container\" *ngIf=\"disableContent !== 'none'\">\r\n <div\r\n [class.overlay-full]=\"disableContent === 'all'\"\r\n [class.overlay-popout-google]=\"\r\n configuredViewer === 'google' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [class.overlay-popout-office]=\"\r\n configuredViewer === 'office' &&\r\n (disableContent === 'popout' || disableContent === 'popout-hide')\r\n \"\r\n [style.background-color]=\"\r\n disableContent === 'popout-hide' ? '#fff' : 'transparent'\r\n \"\r\n ></div>\r\n <iframe\r\n (load)=\"iframeLoaded()\"\r\n *ngIf=\"fullUrl\"\r\n #iframe\r\n id=\"iframe\"\r\n frameBorder=\"0\"\r\n [src]=\"fullUrl\"\r\n ></iframe>\r\n </div>\r\n</ng-container>\r\n","import { NgxDocViewerComponent } from './document-viewer.component';\r\nimport { NgModule } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n\r\n@NgModule({\r\n imports: [CommonModule],\r\n declarations: [NgxDocViewerComponent],\r\n exports: [NgxDocViewerComponent],\r\n})\r\nexport class NgxDocViewerModule {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}